Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r4d7d40a27130dc813d653f044cbb856b1b7d8481 -rc31c6e4340c28577df4d146165ccbfc8f0a47134 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 4d7d40a27130dc813d653f044cbb856b1b7d8481) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision c31c6e4340c28577df4d146165ccbfc8f0a47134) @@ -14,624 +14,910 @@ * @date (original) 04-Apr-2020 * ***************************************************************************/ - -#include - -#include "etpwm.h" -#include "mibspi.h" - -#include "FPGA.h" -#include "OperationModes.h" -#include "PIControllers.h" -#include "Pressures.h" -#include "ROPump.h" -#include "SystemCommMessages.h" -#include "TaskGeneral.h" -#include "TaskPriority.h" -#include "Timers.h" -#ifdef EMC_TEST_BUILD -#include "Heaters.h" -#endif -#ifdef ENABLE_DIP_SWITCHES -#include "Valves.h" -#endif - -/** - * @addtogroup ROPump - * @{ - */ - -// ********** private definitions ********** - -#define RO_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the RO Pump data is published on the CAN bus. - -#define MAX_RO_PUMP_PWM_STEP_CHANGE 0.01 ///< Max duty cycle change for controller. -#define MAX_RO_PUMP_PWM_DUTY_CYCLE 0.99 ///< Max duty cycle. -#define MIN_RO_PUMP_PWM_DUTY_CYCLE 0.00 ///< Min duty cycle. - -#define ROP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the RO pump is controlled. -#define ROP_P_COEFFICIENT 0.0020 ///< P term for RO pump control. -#define ROP_I_COEFFICIENT 0.0015 ///< I term for RO pump control. - -#define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor). - -#define FLOW_SAMPLES_TO_AVERAGE (250 / TASK_PRIORITY_INTERVAL) ///< Averaging flow data over 250 ms intervals. -#define FLOW_AVERAGE_MULTIPLIER (1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE) ///< Optimization - multiplying is faster than dividing. -// TODO - this is a place holder for real conversion -#define ROP_PSI_TO_PWM_DC(p) ( 0.2 + ( (F32)((p) - 100) * 0.01 ) ) ///< conversion factor from target PSI to PWM duty cycle estimate. -#define RO_FLOW_ADC_TO_LPM_FACTOR 10909.0909 ///< conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). - -/// Enumeration of RO pump states. -typedef enum ROPump_States -{ - RO_PUMP_OFF_STATE = 0, ///< RO pump off state - RO_PUMP_CONTROL_TO_TARGET_STATE, ///< RO pump control to target pressure state - NUM_OF_RO_PUMP_STATES ///< Number of RO pump states -} RO_PUMP_STATE_T; - -/// Enumeration of RO pump self-test states. -typedef enum ROPump_Self_Test_States -{ - RO_PUMP_SELF_TEST_STATE_START = 0, ///< RO pump self-test start state - RO_PUMP_TEST_STATE_IN_PROGRESS, ///< RO pump self-tests in progress state - RO_PUMP_TEST_STATE_COMPLETE, ///< RO pump self-tests completed state - NUM_OF_RO_PUMP_SELF_TEST_STATES ///< Number of RO pump self-test states -} RO_PUMP_SELF_TEST_STATE_T; - -// TODO - test code - remove later -// pin assignments for pump test DIP switch 0 -#define RO_PUMP_TEST_SPI5_PORT_MASK 0x00000100 // (ENA - re-purposed as input GPIO) -// dialIn pump stop and direction macros -#define GET_DIP_SW0_TEST() ( ( mibspiREG5->PC2 & RO_PUMP_TEST_SPI5_PORT_MASK ) != 0 ) - -// ********** private data ********** - -static RO_PUMP_STATE_T roPumpState = RO_PUMP_OFF_STATE; ///< Current state of RO pump controller state machine. -static U32 roPumpDataPublicationTimerCounter = 0; ///< RO pump data publication timer counter. -static BOOL isROPumpOn = FALSE; ///< RO pump is currently running. -static F32 roPumpPWMDutyCyclePct = 0.0; ///< Initial RO pump PWM duty cycle. -static F32 roPumpPWMDutyCyclePctSet = 0.0; ///< Currently set RO pump PWM duty cycle. -static PUMP_CONTROL_MODE_T roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Requested RO pump control mode. -static PUMP_CONTROL_MODE_T roPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< Currently set RO pump control mode. - +#include + +#include "etpwm.h" +#include "mibspi.h" + +#include "FPGA.h" +#include "OperationModes.h" +#include "PIControllers.h" +#include "PersistentAlarm.h" +#include "Pressures.h" +#include "ROPump.h" +#include "SystemCommMessages.h" +#include "TaskGeneral.h" +#include "TaskPriority.h" +#include "Timers.h" +#ifdef EMC_TEST_BUILD +#include "Heaters.h" +#endif +#ifdef ENABLE_DIP_SWITCHES +#include "Valves.h" +#endif + +/** + * @addtogroup ROPump + * @{ + */ + +// ********** private definitions ********** + +#define RO_PUMP_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Interval (ms/task time) at which the RO Pump data is published on the CAN bus. + +#define MAX_RO_PUMP_DUTY_CYCLE 0.99 ///< max duty cycle. +#define MIN_RO_PUMP_DUTY_CYCLE 0.0 ///< min duty cycle. + +#define ROP_CONTROL_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< interval (ms/task time) at which the RO pump is controlled. +#define ROP_P_COEFFICIENT 0.0020 ///< P term for RO pump pressure control. +#define ROP_I_COEFFICIENT 0.0015 ///< I term for RO pump pressure control. + +#define ROP_RAMP_UP_P_COEFFICIENT 0.0 ///< P term for RO pump flow control. +#define ROP_RAMP_UP_I_COEFFICIENT 0.1 ///< I term for RO pump flow control. +#define ROP_FLOW_TARGET_TOLERANCE 0.05 ///< Tolerance in between the target flow rate and the actual flow rate in liter. + +#define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor). + +#define FLOW_SAMPLES_TO_AVERAGE ( 250 / TASK_PRIORITY_INTERVAL ) ///< Averaging flow data over 250 ms intervals. +#define FLOW_AVERAGE_MULTIPLIER ( 1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. +#define FLOW_VERIFICATION_COUNTER_TARGET 40U ///< The time in counts to check the flow and make sure it is in range. + +#define RO_FLOW_ADC_TO_LPM_FACTOR 10909.0909 ///< conversion factor from ADC counts to LPM (liters/min) for RO flow rate (multiply this by inverse of FPGA reading). + +#define ROP_FLOW_TO_PWM_DC(flow) ( (F32)( flow / MAX_RO_FLOWRATE_LPM ) ) ///< Initial conversion factor from target flow rate to PWM duty cycle estimate. + +#define FLOW_SENSOR_ZERO_READING 0xFFFF ///< Flow sensor reading indicates zero flow (or flow lower than can be detected by sensor). + +#define FLOW_SAMPLES_TO_AVERAGE ( 250 / TASK_PRIORITY_INTERVAL ) ///< Averaging flow data over 250 ms intervals. +#define FLOW_AVERAGE_MULTIPLIER ( 1.0 / (F32)FLOW_SAMPLES_TO_AVERAGE ) ///< Optimization - multiplying is faster than dividing. +#define MAX_ALLOWED_FLOW_DEVIATION 0.1 ///< Max allowed deviation from target flow. +#define FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL 5 * MS_PER_SECOND ///< Flow out of range time out in counts. +#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 ( 30 * MS_PER_SECOND ) ///< Maximum allowed ramp up time to a flow rate in ms. +#define RAMP_UP_TIME_OUT_COUNT ( MAX_ALLOWED_RAMP_UP_TIME / \ + TASK_GENERAL_INTERVAL ) ///< Ramp up time out in counts. +#define ROP_PSI_TO_PWM_DC(p) ( 0.2 + ( (F32)((p) - 100) * 0.01 ) ) ///< conversion factor from target PSI to PWM duty cycle estimate. TODO remove? + +/// Enumeration of RO pump states. +typedef enum ROPump_States +{ + RO_PUMP_OFF_STATE = 0, ///< RO pump off state + RO_PUMP_RAMP_UP_STATE, ///< RO pump ramp up to target flow rate state + RO_PUMP_VERIFY_FLOW_STATE, ///< RO pump maintain the flow rate for a set period of time + RO_PUMP_CONTROL_TO_TARGET_STATE, ///< RO pump control to target pressure state + RO_PUMP_OPEN_LOOP_STATE, ///< RO pump open loop state + NUM_OF_RO_PUMP_STATES ///< Number of RO pump states +} RO_PUMP_STATE_T; + +/// Enumeration of RO pump self-test states. +typedef enum ROPump_Self_Test_States +{ + RO_PUMP_SELF_TEST_STATE_START = 0, ///< RO pump self-test start state + RO_PUMP_TEST_STATE_IN_PROGRESS, ///< RO pump self-tests in progress state + RO_PUMP_TEST_STATE_COMPLETE, ///< RO pump self-tests completed state + NUM_OF_RO_PUMP_SELF_TEST_STATES ///< Number of RO pump self-test states +} RO_PUMP_SELF_TEST_STATE_T; + +// ********** private data ********** + +static RO_PUMP_STATE_T roPumpState = RO_PUMP_OFF_STATE; ///< current state of RO pump controller state machine +static U32 roPumpDataPublicationTimerCounter = 0; ///< used to schedule RO pump data publication to CAN bus +static BOOL isROPumpOn = FALSE; ///< RO pump is currently running +static F32 roPumpPWMDutyCyclePct = 0.0; ///< initial RO pump PWM duty cycle +static F32 roPumpDutyCyclePctSet = 0.0; ///< currently set RO pump PWM duty cycle +static PUMP_CONTROL_MODE_T roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< requested RO pump control mode +static PUMP_CONTROL_MODE_T roPumpControlModeSet = PUMP_CONTROL_MODE_CLOSED_LOOP; ///< currently set RO pump control mode + +static F32 targetROPumpFlowRate = 0.0; ///< Target RO flow rate (in L/min) +static U32 targetROPumpPressure = 0; ///< Target RO pressure (in PSI) + static OVERRIDE_U32_T roPumpDataPublishInterval = { RO_PUMP_DATA_PUB_INTERVAL, - RO_PUMP_DATA_PUB_INTERVAL, 0, 0 }; ///< Interval (in ms) at which to publish RO flow data to CAN bus. -static OVERRIDE_U32_T targetROPumpPressure = { 0, 0, 0, 0 }; ///< Target RO pressure (in PSI). -static OVERRIDE_F32_T measuredROFlowRateLPM = { 0.0, 0.0, 0.0, 0 }; ///< Measured RO flow rate (in LPM). -static F32 measuredROPumpPressure = 0.0; ///< Measured RO pressure (in PSI). - -static S32 measuredFlowReadingsSum = 0; ///< Raw flow reading sums for averaging. -static U32 flowFilterCounter = 0; ///< Flow filtering counter. - -static U32 roControlTimerCounter = 0; ///< Timer counter for perform control on RO pump. - -static RO_PUMP_SELF_TEST_STATE_T roPumpSelfTestState = RO_PUMP_SELF_TEST_STATE_START; ///< Current RO pump self-test state. -static U32 roPumpSelfTestTimerCount = 0; ///< Timer counter for RO pump self-test. - -// ********** private function prototypes ********** - -static RO_PUMP_STATE_T handleROPumpOffState( void ); -static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ); -static void setROPumpControlSignalPWM( F32 newPWM ); -static void stopROPump( void ); -static void publishROPumpData( void ); -static U32 getPublishROPumpDataInterval( void ); - -/*********************************************************************//** - * @brief - * The initROPump function initializes the ROPump module. - * @details Inputs: none - * @details Outputs: ROPump module initialized. - * @return none - *************************************************************************/ -void initROPump( void ) -{ - stopROPump(); - - // initialize RO pump PI controller - initializePIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_PWM_DUTY_CYCLE, ROP_P_COEFFICIENT, - ROP_I_COEFFICIENT, MIN_RO_PUMP_PWM_DUTY_CYCLE, MAX_RO_PUMP_PWM_DUTY_CYCLE ); -} - -/*********************************************************************//** - * @brief - * The setROPumpTargetPressure function sets a new target pressure for the RO pump. - * @details Inputs: none - * @details Outputs: targetROPumpPressure, roPumpPWMDutyCyclePct - * @param roPressure new target RO pressure - * @param mode new control mode - * @return TRUE if new target pressure is set, FALSE if not - *************************************************************************/ -BOOL setROPumpTargetPressure( U32 roPressure, PUMP_CONTROL_MODE_T mode ) -{ - BOOL result = FALSE; - - // verify pressure - if ( roPressure >= MIN_RO_PRESSURE && roPressure <= MAX_RO_PRESSURE ) - { - targetROPumpPressure.data = roPressure; - roPumpControlMode = mode; - // set PWM duty cycle target to an estimated initial target based on target pressure - then we'll control to pressure going forward -#ifdef EMC_TEST_BUILD - roPumpPWMDutyCyclePct = 1.0; -#else - roPumpPWMDutyCyclePct = ROP_PSI_TO_PWM_DC( roPressure ); -#endif - - result = TRUE; - } - else // requested pressure out of range - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, 0, roPressure ) // TODO - replace 1st param with s/w fault enum - } - - return result; -} - -/*********************************************************************//** - * @brief - * The signalROPumpHardStop function stops the RO pump immediately. - * @details Inputs: none - * @details Outputs: RO pump stopped, set point reset, state changed to off - * @return none - *************************************************************************/ -void signalROPumpHardStop( void ) -{ - targetROPumpPressure.data = 0; - stopROPump(); - roPumpState = RO_PUMP_OFF_STATE; - roPumpPWMDutyCyclePct = 0.0; - roControlTimerCounter = 0; - resetPIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_PWM_DUTY_CYCLE ); -} - -/*********************************************************************//** - * @brief - * The execROPumpMonitor function executes the RO Pump monitor. - * @details Inputs: flowFilterCounter - * @details Outputs: measuredROPumpPressure, measuredROFlowRateLPM - * @return none - *************************************************************************/ -void execROPumpMonitor( void ) -{ - U16 roFlowReading = getFPGAROPumpFlowRate(); - S32 roFlow = (S32)roFlowReading; - - // update sum for flow average calculation - measuredFlowReadingsSum += roFlow; - // filter every 250ms - if ( ++flowFilterCounter >= FLOW_SAMPLES_TO_AVERAGE ) - { - F32 avgROFlow = (F32)measuredFlowReadingsSum * FLOW_AVERAGE_MULTIPLIER; - - if ( ( avgROFlow == FLOW_SENSOR_ZERO_READING ) || ( measuredFlowReadingsSum == 0 ) ) - { - measuredROFlowRateLPM.data = 0.0; - } - else - { - measuredROFlowRateLPM.data = RO_FLOW_ADC_TO_LPM_FACTOR / avgROFlow; - } - measuredFlowReadingsSum = 0; - flowFilterCounter = 0; - } - - measuredROPumpPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); - - // TODO - check pressure? - - // TODO - check flow? - - // publish RO pump data on interval - publishROPumpData(); -} - -/*********************************************************************//** - * @brief - * The execROPumpController function executes the RO Pump controller. - * @details Inputs: roPumpState - * @details Outputs: roPumpState - * @return none - *************************************************************************/ -void execROPumpController( void ) -{ - switch ( roPumpState ) - { - case RO_PUMP_OFF_STATE: - roPumpState = handleROPumpOffState(); - break; - - case RO_PUMP_CONTROL_TO_TARGET_STATE: - roPumpState = handleROPumpControlToTargetState(); - break; - - default: - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, 0, roPumpState ) // TODO - replace 1st param with s/w fault enum - roPumpState = RO_PUMP_OFF_STATE; - break; - } -} - -/*********************************************************************//** - * @brief - * The isROPumpOn function returns the status of RO pump. - * @details Inputs: none - * @details Outputs: none - * @return isROPumpOn - *************************************************************************/ -BOOL isReverseOsmosisPumpOn( void ) -{ - return isROPumpOn; -} - -/*********************************************************************//** - * @brief + RO_PUMP_DATA_PUB_INTERVAL, + 0, 0 }; ///< Interval (in ms) at which to publish RO flow data to CAN bus +static OVERRIDE_F32_T measuredROFlowRateLPM = { 0.0, 0.0, 0.0, 0 }; ///< measured RO flow rate (in L/min) + +static U32 flowVerificationCounter = 0; ///< Counter to verify the flow is in range +static U32 roControlTimerCounter = 0; ///< determines when to perform control on RO pump +static F32 roPumpOpenLoopTargetDutyCycle = 0; ///< Target RO pump open loop PWM +static F32 roPumpFlowRateRunningSum = 0; ///< RO pump flow rate running sum +static F32 roPumpPressureRunningSum = 0; ///< RO pump pressure running sum + +/* These variables are used for POST. POST has not been implemented yet +static RO_PUMP_SELF_TEST_STATE_T roPumpSelfTestState = RO_PUMP_SELF_TEST_STATE_START; ///< Current ro pump self test state +static U32 roPumpSelfTestTimerCount = 0; ///< Timer counter for ro pump self test +*/ + +static S32 measuredFlowReadingsSum = 0; ///< Raw flow reading sums for averaging +static U32 flowFilterCounter = 0; ///< Flow filtering counter +static U32 rampUp2FlowTimeoutCounter = 0; ///< Counter for ramping up to flow time + +// ********** private function prototypes ********** + +static RO_PUMP_STATE_T handleROPumpOffState( void ); +static RO_PUMP_STATE_T handleROPumpRampUpState( void ); +static RO_PUMP_STATE_T handleROPumpVerifyFlowState( void ); +static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ); +static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ); + +static void setROPumpTargetDutyCycle( F32 duty ); +static void setROPumpControlSignalDutyCycle( F32 dutyCycle ); +static void stopROPump( void ); +static void publishROPumpData( void ); +static U32 getPublishROPumpDataInterval( void ); + +/*********************************************************************//** + * @brief + * The initROPump function initializes the RO Pump module. + * @details Inputs: rampUp2FlowTimeoutCounter + * @details Outputs: rampUp2FlowTimeoutCounter + * @return none + *************************************************************************/ +void initROPump( void ) +{ + stopROPump(); + + // Initialize RO pump PI controller + initializePIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_DUTY_CYCLE, ROP_P_COEFFICIENT, ROP_I_COEFFICIENT, + MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE ); + + // Initialize the I controller during ramp up + initializePIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, MIN_RO_PUMP_DUTY_CYCLE, ROP_RAMP_UP_P_COEFFICIENT, ROP_RAMP_UP_I_COEFFICIENT, + MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE ); + + // Initialize the persistent alarm for flow out of upper and lower range + initPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_UPPER_RANGE, ALARM_ID_FLOW_RATE_OUT_OF_RANGE, TRUE, + FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + + initPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_LOWER_RANGE, ALARM_ID_FLOW_RATE_OUT_OF_RANGE, TRUE, + FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL, FLOW_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + + // Initialize the persistent alarm for max allowed pressure out of range + initPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_PRESSURE_OUT_OF_RANGE, ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, TRUE, + MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL, MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + + // Initialize the variables + rampUp2FlowTimeoutCounter = 0; + roControlTimerCounter = 0; + roPumpOpenLoopTargetDutyCycle = 0; + roPumpFlowRateRunningSum = 0; + roPumpPressureRunningSum = 0; + measuredFlowReadingsSum = 0; + flowFilterCounter = 0; + rampUp2FlowTimeoutCounter = 0; + flowVerificationCounter = 0; + roPumpDataPublicationTimerCounter = 0; + roPumpState = RO_PUMP_OFF_STATE; + roPumpControlMode = NUM_OF_PUMP_CONTROL_MODES; + roPumpControlModeSet = roPumpControlMode; +} + +/*********************************************************************//** + * @brief + * The setROPumpTargetDutyCycle function sets the duty cycle that the + * pump should run. + * @details Inputs: roPumpOpenLoopTargetDutyCycle, roPumpPWMDutyCyclePct, + * roPumpPWMDutyCyclePctSet, roPumpControlMode + * @details Outputs: roPumpOpenLoopTargetDutyCycle, roPumpPWMDutyCyclePct, + * roPumpPWMDutyCyclePctSet, roPumpControlMode + * @param: duty which is the duty cycle + * @return none + *************************************************************************/ +static void setROPumpTargetDutyCycle( F32 duty ) +{ + roPumpOpenLoopTargetDutyCycle = duty; + roPumpPWMDutyCyclePct = roPumpOpenLoopTargetDutyCycle; + roPumpDutyCyclePctSet = roPumpPWMDutyCyclePct; + roPumpControlMode = PUMP_CONTROL_MODE_OPEN_LOOP; +} + +/*********************************************************************//** + * @brief + * The setROPumpTargetFlowRate function sets a new target flow rate for the + * RO pump. + * @details Inputs: targetROPumpPressure, targetROPumpFlowRate, + * roPumpControlMode, rampUp2FlowTimeoutCounter + * @details Outputs: targetROPumpPressure, targetROPumpFlowRate, + * roPumpControlMode, rampUp2FlowTimeoutCounter + * @param roFlowRate which is target RO flow rate + * @param maxPressure which is the maximum allowed pressure that the RO pump + * can reach + * @return TRUE if new target flow rate is set successfully, FALSE if not + *************************************************************************/ +BOOL setROPumpTargetFlowRate( F32 roFlowRate, U32 maxPressure ) +{ + BOOL result = FALSE; + + // First of all, the flow rate must be in range + if ( ( roFlowRate < MAX_RO_FLOWRATE_LPM ) && ( roFlowRate >= MIN_RO_FLOWRATE_LPM ) ) + { + // Then the max pressure that we are allowed to reach must be in range + if ( ( maxPressure >= MIN_ALLOWED_PRESSURE_PSI ) && ( maxPressure <= MAX_ALLOWED_PRESSURE_PSI ) ) + { + // For now maximum allowed pressure is inserted into the target pressure override + // if the target flow rate exceeded the max pressure, it will set the maximum pressure + targetROPumpPressure = maxPressure; + targetROPumpFlowRate = roFlowRate; + roPumpControlMode = PUMP_CONTROL_MODE_CLOSED_LOOP; + // Get the initial guess of the duty cycle + roPumpPWMDutyCyclePct = ROP_FLOW_TO_PWM_DC( roFlowRate ); + rampUp2FlowTimeoutCounter = 0; + result = TRUE; + } + // Requested max pressure is out of range + else + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_FLOW_RATE_SET, maxPressure ) + } + } + // Requested flow rate is out of range + else + { + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_PRESSURE_SELECTED, roFlowRate ) + } + + return result; +} + +/*********************************************************************//** + * @brief + * The signalROPumpHardStop function stops the RO pump immediately and + * resets all the variables associated with the RO pump run. + * @details Inputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, + * roPumpOpenLoopTargetDutyCycle, roControlTimerCounter, flowVerificationCounter, + * flowVerificationCounter, isROPumpOn, rampUp2FlowTimeoutCounter + * @details Outputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, + * roPumpOpenLoopTargetDutyCycle, roControlTimerCounter, + * flowVerificationCounter, isROPumpOn, rampUp2FlowTimeoutCounter + * @return none + *************************************************************************/ +void signalROPumpHardStop( void ) +{ + stopROPump(); + targetROPumpFlowRate = 0; + roPumpState = RO_PUMP_OFF_STATE; + roPumpPWMDutyCyclePct = 0.0; + roPumpOpenLoopTargetDutyCycle = 0.0; + roControlTimerCounter = 0; + flowVerificationCounter = 0; + isROPumpOn = FALSE; + rampUp2FlowTimeoutCounter = 0; + targetROPumpPressure = 0; + resetPIController( PI_CONTROLLER_ID_RO_PUMP, MIN_RO_PUMP_DUTY_CYCLE ); +} + +/*********************************************************************//** + * @brief + * The execROPumpMonitor function executes the RO pump monitor. + * @details Inputs: measuredFlowReadingsSum, flowFilterCounter, + * measuredROFlowRateLPM, measuredROFlowRateLPM, roPumpState, + * flowOutOfRangeCounter, roPumpControlMode + * @details Outputs: measuredFlowReadingsSum, flowFilterCounter, + * measuredROFlowRateLPM, measuredROFlowRateLPM + * @return none + *************************************************************************/ +void execROPumpMonitor( void ) +{ + U16 roFlowReading = getFPGAROPumpFlowRate(); + S32 roFlow = (S32)roFlowReading; + // Update sum for flow average calculation + measuredFlowReadingsSum += roFlow; + + // Read the pressure at the sensor. The pump cannot be more that the maximum allowed pressure + // 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; + checkPersistentAlarm( PERSISTENT_ALARM_RO_PUMP_PRESSURE_OUT_OF_RANGE, isPressureMax, actualPressure ); + + // Read flow at the control set + if ( ++flowFilterCounter >= FLOW_SAMPLES_TO_AVERAGE ) + { + F32 avgROFlow = (F32)measuredFlowReadingsSum * FLOW_AVERAGE_MULTIPLIER; + + // If the flow is less than a certain value, FPGA will return 0xFFFF meaning that + // the flow is 0. Otherwise, convert the count to flow rate in mL/min + if ( ( roFlowReading == FLOW_SENSOR_ZERO_READING ) || ( roFlowReading == 0 ) ) + { + measuredROFlowRateLPM.data = 0.0; + } + else + { + measuredROFlowRateLPM.data = RO_FLOW_ADC_TO_LPM_FACTOR / avgROFlow; + } + + measuredFlowReadingsSum = 0; + flowFilterCounter = 0; + } + + // To monitor the flow, the control mode must be in closed loop and the pump should be control to target state, + // meaning, it is controlling to a certain pressure + if ( roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP && roPumpState == RO_PUMP_CONTROL_TO_TARGET_STATE ) + { + F32 currentFlow = getMeasuredROFlowRate(); + F32 targetFlow = getTargetROPumpFlowRate(); + F32 error = fabs( 1.0 - ( currentFlow / targetFlow ) ); + BOOL isFlowOutOfRange = error > MAX_ALLOWED_FLOW_DEVIATION; + + // Figure out whether flow is out of range from which side + if ( isFlowOutOfRange ) + { + //BOOL isFlowOutOfUpperRange = currentFlow > targetFlow; + //BOOL isFlowOutOfLowerRange = currentFlow < targetFlow; + if ( currentFlow > targetFlow ) + { + checkPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_UPPER_RANGE, TRUE, currentFlow ); + } + else + { + checkPersistentAlarm( PERSISTENT_ALARM_RO_FLOW_RATE_OUT_OF_LOWER_RANGE, TRUE, currentFlow ); + } + } + } + + // Publish RO pump data on interval + publishROPumpData(); +} + +/*********************************************************************//** + * @brief + * The execROPumpController function executes the RO pump controller. + * @details Inputs: roPumpState + * @details Outputs: roPumpState + * @return none + *************************************************************************/ +void execROPumpController( void ) +{ + switch ( roPumpState ) + { + case RO_PUMP_OFF_STATE: + roPumpState = handleROPumpOffState(); + break; + + case RO_PUMP_RAMP_UP_STATE: + roPumpState = handleROPumpRampUpState(); + break; + + case RO_PUMP_VERIFY_FLOW_STATE: + roPumpState = handleROPumpVerifyFlowState(); + break; + + case RO_PUMP_CONTROL_TO_TARGET_STATE: + roPumpState = handleROPumpControlToTargetState(); + break; + + case RO_PUMP_OPEN_LOOP_STATE: + roPumpState = handleROPumpOpenLoopState(); + break; + + default: + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_RO_PUMP_INVALID_EXEC_STATE, roPumpState ) + roPumpState = RO_PUMP_OFF_STATE; + break; + } +} + +/*********************************************************************//** + * @brief + * The isReverseOsmosisPumpOn function returns the on/off status of RO pump. + * @details Inputs: isROPumpOn + * @details Outputs: none + * @return isROPumpOn the boolean flag that is TRUE if the pump is on and + * FALSE if it is off + *************************************************************************/ +BOOL isReverseOsmosisPumpOn( void ) +{ + return isROPumpOn; +} + +/*********************************************************************//** + * @brief + * The execROPumpTest function executes the state machine for the RO pump + * self-test. + * @details + * Inputs: TODO FILL UP + * Outputs: TODO FILL UP + * @return the current state of the ROPump self test. + *************************************************************************/ +SELF_TEST_STATUS_T execROPumpTest( void ) +{ + SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; + + // TODO - implement self-test(s) + + return result; +} + +/*********************************************************************//** + * @brief * The handleROPumpOffState function handles the RO pump off state of the - * RO pump controller state machine. - * @details Inputs: targetROPumpPressure - * @details Outputs: roPumpPWMDutyCyclePctSet, isROPumpOn - * @return next state - *************************************************************************/ -static RO_PUMP_STATE_T handleROPumpOffState( void ) -{ - RO_PUMP_STATE_T result = RO_PUMP_OFF_STATE; - -#ifdef DEBUG_ENABLED -#ifdef ENABLE_DIP_SWITCHES - // TODO - test code - remove later - if ( GET_DIP_SW0_TEST() ) - { - setValveState( VSP, VALVE_STATE_CLOSED ); - setValveState( VPI, VALVE_STATE_OPEN ); - setValveState( VPO, VALVE_STATE_NOFILL_C_TO_NO ); - setValveState( VRC, VALVE_STATE_DRAIN_C_TO_NO ); - setValveState( VDR, VALVE_STATE_DRAIN_C_TO_NO ); - setROPumpTargetPressure( 120, PUMP_CONTROL_MODE_CLOSED_LOOP ); -#ifdef EMC_TEST_BUILD - { - 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 ) ) ); - setPrimaryHeaterTargetTemperature( 50.0 ); - startPrimaryHeater(); - } -#endif - } -#endif -#endif - - // if we've been given a pressure, transition to control to target state - if ( getTargetROPumpPressure() > 0 ) - { - roPumpControlModeSet = roPumpControlMode; - // set initial PWM duty cycle - roPumpPWMDutyCyclePctSet = roPumpPWMDutyCyclePct; - setROPumpControlSignalPWM( roPumpPWMDutyCyclePctSet ); - // reset controller - resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpPWMDutyCyclePctSet ); - // set pump to on - isROPumpOn = TRUE; - result = RO_PUMP_CONTROL_TO_TARGET_STATE; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The handleROPumpControlToTargetState function handles the "control to - * target" state of the RO pump controller state machine. - * @details Inputs: none - * @details Outputs: roPumpState - * @return next state - *************************************************************************/ -static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ) -{ - RO_PUMP_STATE_T result = RO_PUMP_CONTROL_TO_TARGET_STATE; - - // control at set interval - if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) - { - if ( roPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) - { - F32 tgtPres = (F32)getTargetROPumpPressure(); - F32 actPres = measuredROPumpPressure; - F32 newPWM; - -#ifndef EMC_TEST_BUILD - newPWM = runPIController( PI_CONTROLLER_ID_RO_PUMP, tgtPres, actPres ); - roPumpPWMDutyCyclePctSet = newPWM; - setROPumpControlSignalPWM( newPWM ); -#endif - } - roControlTimerCounter = 0; - } - -#ifdef DEBUG_ENABLED -#ifdef ENABLE_DIP_SWITCHES - // TODO - test code - remove later - if ( !GET_DIP_SW0_TEST() ) - { - signalROPumpHardStop(); - result = RO_PUMP_OFF_STATE; -#ifdef EMC_TEST_BUILD - etpwmSetCmpA( etpwmREG6, 0 ); - etpwmSetCmpB( etpwmREG6, 0 ); - stopPrimaryHeater(); -#endif - } -#endif -#endif - - return result; -} - -/*********************************************************************//** - * @brief - * The setROPumpControlSignalPWM function sets the PWM duty cycle for the - * RO pump to a given %. - * @details Inputs: none - * @details Outputs: PWM duty cycle zeroed - * @param newPWM new duty cycle % to apply to PWM - * @return none - *************************************************************************/ -static void setROPumpControlSignalPWM( F32 newPWM ) -{ - etpwmSetCmpB( etpwmREG2, (U32)( (S32)( ( newPWM * (F32)(etpwmREG2->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); -} - -/*********************************************************************//** - * @brief - * The stopROPump function sets the RO pump PWM to zero. - * @details Inputs: none - * @details Outputs: PWM duty cycle zeroed - * @return none - *************************************************************************/ -static void stopROPump( void ) -{ - isROPumpOn = FALSE; - roPumpPWMDutyCyclePctSet = 0.0; - etpwmSetCmpB( etpwmREG2, 0 ); -} - -/*********************************************************************//** - * @brief - * The getPublishROPumpDataInterval function gets the RO pump data publish interval. - * @details Inputs: roPumpDataPublishInterval - * @details Outputs: none - * @return the current RO pump data publication interval (in ms). - *************************************************************************/ -static U32 getPublishROPumpDataInterval( void ) -{ - U32 result = roPumpDataPublishInterval.data; - - if ( OVERRIDE_KEY == roPumpDataPublishInterval.override ) - { - result = roPumpDataPublishInterval.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The getTargetROPumpPressure function gets the current target RO pump pressure. - * @details Inputs: targetROPumpPressure - * @details Outputs: none - * @return the current target RO pressure (in PSI). - *************************************************************************/ -U32 getTargetROPumpPressure( void ) -{ - U32 result = targetROPumpPressure.data; - - if ( OVERRIDE_KEY == targetROPumpPressure.override ) - { - result = targetROPumpPressure.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The getMeasuredROFlowRate function gets the measured RO pump flow rate. - * @details Inputs: measuredROFlowRateLPM - * @details Outputs: none - * @return the current RO pump flow rate (in LPM). - *************************************************************************/ -F32 getMeasuredROFlowRate( void ) -{ - F32 result = measuredROFlowRateLPM.data; - - if ( OVERRIDE_KEY == measuredROFlowRateLPM.override ) - { - result = measuredROFlowRateLPM.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The publishROPumpData function publishes RO pump data at the set interval. - * @details Inputs: target pressure, measured pressure, measured RO pump speed. - * @details Outputs: RO pump data is published to CAN bus. - * @return none - *************************************************************************/ -static void publishROPumpData( void ) -{ - // publish RO pump data on interval - if ( ++roPumpDataPublicationTimerCounter >= getPublishROPumpDataInterval() ) - { - U32 presStPt = getTargetROPumpPressure(); - F32 measFlow = getMeasuredROFlowRate(); - F32 pumpPWMPctDutyCycle = roPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; - broadcastROPumpData( presStPt, measFlow, pumpPWMPctDutyCycle ); - roPumpDataPublicationTimerCounter = 0; - } -} - -/*********************************************************************//** - * @brief - * The execROPumpTest function executes the state machine for the ROPump self-test. - * @details Inputs: none - * @details Outputs: none - * @return the current state of the ROPump self-test. - *************************************************************************/ -SELF_TEST_STATUS_T execROPumpTest( void ) -{ - SELF_TEST_STATUS_T result = SELF_TEST_STATUS_FAILED; - - // TODO - implement self-test(s) - - return result; -} - - -/************************************************************************* - * TEST SUPPORT FUNCTIONS - *************************************************************************/ + * controller state machine. + * @details Inputs: roPumpControlMode, roPumpControlModeSet, roPumpControlMode, + * roPumpPWMDutyCyclePctSet, roPumpPWMDutyCyclePct, isROPumpOn, + * roPumpOpenLoopTargetDutyCycle + * @details Outputs: roPumpControlModeSet, roPumpPWMDutyCyclePctSet, + * roPumpPWMDutyCyclePct, isROPumpOn + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpOffState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_OFF_STATE; - -/*********************************************************************//** - * @brief - * The testSetROPumpDataPublishIntervalOverride function overrides the - * RO pump data publish interval. - * @details Inputs: none - * @details Outputs: roPumpDataPublishInterval - * @param value override RO pump data publish interval with (in ms) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetROPumpDataPublishIntervalOverride( U32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - U32 intvl = value / TASK_PRIORITY_INTERVAL; - - result = TRUE; - roPumpDataPublishInterval.ovData = intvl; - roPumpDataPublishInterval.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetROPumpDataPublishIntervalOverride function resets the override - * of the RO pump data publish interval. - * @details Inputs: none - * @details Outputs: roPumpDataPublishInterval - * @return TRUE if override reset successful, FALSE if not - *************************************************************************/ -BOOL testResetROPumpDataPublishIntervalOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - roPumpDataPublishInterval.override = OVERRIDE_RESET; - roPumpDataPublishInterval.ovData = roPumpDataPublishInterval.ovInitData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetTargetROPumpPressureOverride function overrides the target - * RO pressure. - * @details Inputs: none - * @details Outputs: targetROPumpPressure - * @param value override target RO pressure (in PSI) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetTargetROPumpPressureOverride( U32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - targetROPumpPressure.ovInitData = targetROPumpPressure.data; // backup current target pressure - targetROPumpPressure.ovData = value; - targetROPumpPressure.override = OVERRIDE_KEY; - result = setROPumpTargetPressure( value, roPumpControlMode ); - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetTargetROPumpPressureOverride function resets the override of the - * target RO pressure. - * @details Inputs: none - * @details Outputs: targetROPumpPressure - * @return TRUE if override reset successful, FALSE if not - *************************************************************************/ -BOOL testResetTargetROPumpPressureOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - targetROPumpPressure.data = targetROPumpPressure.ovInitData; // restore pre-override target pressure - targetROPumpPressure.override = OVERRIDE_RESET; - targetROPumpPressure.ovInitData = 0; - targetROPumpPressure.ovData = 0; - result = setROPumpTargetPressure( targetROPumpPressure.data, roPumpControlMode ); - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testSetMeasuredROFlowRateOverride function overrides the measured - * RO flow rate. - * @details Inputs: none - * @details Outputs: measuredROFlowRateLPM - * @param value override measured RO pump motor speed (in LPM) - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testSetMeasuredROFlowRateOverride( F32 value ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - measuredROFlowRateLPM.ovData = value; - measuredROFlowRateLPM.override = OVERRIDE_KEY; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The testResetMeasuredROFlowRateOverride function resets the override of the - * measured RO flow rate. - * @details Inputs: none - * @details Outputs: measuredROFlowRateLPM - * @return TRUE if override successful, FALSE if not - *************************************************************************/ -BOOL testResetMeasuredROFlowRateOverride( void ) -{ - BOOL result = FALSE; - - if ( TRUE == isTestingActivated() ) - { - result = TRUE; - measuredROFlowRateLPM.override = OVERRIDE_RESET; - measuredROFlowRateLPM.ovData = measuredROFlowRateLPM.ovInitData; - } - - return result; -} + // If there is a flow, transition to the PI controller to get the corresponding pressure of that flow + if ( getTargetROPumpFlowRate() > 0 && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) + { + roPumpControlModeSet = roPumpControlMode; + // Set initial PWM duty cycle + roPumpDutyCyclePctSet = roPumpPWMDutyCyclePct; + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + // Reset controller + resetPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, roPumpDutyCyclePctSet ); + // Set pump to on + isROPumpOn = TRUE; + result = RO_PUMP_RAMP_UP_STATE; + } + // If the target duty cycle is greater than zero (minimum is 10%) and the mode has been set to open + // loop, set the duty cycle + if ( roPumpOpenLoopTargetDutyCycle > 0 && roPumpControlMode == PUMP_CONTROL_MODE_OPEN_LOOP ) + { + setROPumpControlSignalDutyCycle( roPumpOpenLoopTargetDutyCycle ); + isROPumpOn = TRUE; + result = RO_PUMP_OPEN_LOOP_STATE; + } + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpRampUpState function handles the RO pump ramp up state + * of the controller state machine. + * @details Inputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, + * rampUp2FlowTimeoutCounter + * @details Outputs: roControlTimerCounter, roPumpPWMDutyCyclePctSet, + * rampUp2FlowTimeoutCounter + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpRampUpState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_RAMP_UP_STATE; + + // Get the current pressure from the sensor + F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + // If we are still in the ramp up mode after the specified time, get the current pressure + // and control from this + if ( ++rampUp2FlowTimeoutCounter > RAMP_UP_TIME_OUT_COUNT ) + { + targetROPumpPressure = actualPressure; + rampUp2FlowTimeoutCounter = 0; + result = RO_PUMP_CONTROL_TO_TARGET_STATE; + } + // Control at set interval + else if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) + { + F32 targetFlowRate = getTargetROPumpFlowRate(); + F32 actualFlowRate = (F32)getMeasuredROFlowRate(); + + // If the actual pressure is greater than the target pressure or it is within the tolerance of the maximum pressure, move to set + // to target pressure straight. At the beginning the maximum pressure is set in the targetROPumpPressure override variable. + // If the flow rate was reached without reaching to maximum pressure, the pressure that was set to targetROPumpPressure override will + // be reset to the corresponding pressure of the target flow rate. + if ( actualPressure > getTargetROPumpPressure() || ( getTargetROPumpPressure() - actualPressure ) > MAX_PRESSURE_TARGET_TOLERANCE ) + { + result = RO_PUMP_CONTROL_TO_TARGET_STATE; + } + // If the actual flow is still far from target flow, update the duty cycle using the I controller and stay in this state + else if ( fabs( actualFlowRate - targetFlowRate ) > ROP_FLOW_TARGET_TOLERANCE ) + { + roPumpDutyCyclePctSet = runPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, targetFlowRate, actualFlowRate ); + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + } + // Reached to the target flow go to the next state + else + { + result = RO_PUMP_VERIFY_FLOW_STATE; + } + + roControlTimerCounter = 0; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpVerifyFlowState function handles the RO pump verify + * flow state of the RO pump controller state machine. + * @details Inputs: flowVerificationCounter, targetROPumpPressure, + * roPumpFlowRateRunningSum, roPumpFlowRateRunningSum + * @details Outputs: flowVerificationCounter, targetROPumpPressure, + * roPumpFlowRateRunningSum, roPumpFlowRateRunningSum + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpVerifyFlowState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_VERIFY_FLOW_STATE; + + // Calculate the running sum of the flow rate and RO pump outlet pressure + roPumpFlowRateRunningSum = roPumpFlowRateRunningSum + (F32)getMeasuredROFlowRate(); + roPumpPressureRunningSum = roPumpPressureRunningSum + getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + // Check if the time for flow verification has elapsed + if ( ++flowVerificationCounter >= FLOW_VERIFICATION_COUNTER_TARGET ) + { + F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + // If the flow has been achieved without reaching to the maximum pressure, set the new pressure + // otherwise, stay with the maximum allowed pressure as target pressure + if ( actualPressure < getTargetROPumpPressure() ) + { + // Calculate the average pressure and flow rate + F32 avgPressure = roPumpPressureRunningSum / flowVerificationCounter; + F32 avgFlowRate = roPumpFlowRateRunningSum / flowVerificationCounter; + + F32 targetFlowRate = getTargetROPumpFlowRate(); + + // Calculate the flow rate deviation from the target flow rate + F32 flowRateDeviation = ( targetFlowRate - avgFlowRate ) / targetFlowRate; + // Use the flow rate deviation to adjust the average calculated pressure. This + // pressure is used as the target pressure + avgPressure = avgPressure + ( avgPressure * flowRateDeviation ); + // Save the target pressure + targetROPumpPressure = avgPressure; + } + + // Reset the I controller for the flow rate as it is no longer needed + resetPIController( I_CONTROLLER_ID_RO_PUMP_RAMP_UP, MIN_RO_PUMP_DUTY_CYCLE ); + + // Set initial PWM duty cycle + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + // Reset controller + resetPIController( PI_CONTROLLER_ID_RO_PUMP, roPumpDutyCyclePctSet ); + // Reset all the variables before leaving + flowVerificationCounter = 0; + roPumpFlowRateRunningSum = 0; + roPumpPressureRunningSum = 0; + result = RO_PUMP_CONTROL_TO_TARGET_STATE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpControlToTargetState function handles the control to + * target state of the RO pump controller state machine. + * @details Inputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter, + * roPumpControlModeSet + * @details Outputs: roPumpPWMDutyCyclePctSet, roControlTimerCounter + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpControlToTargetState( void ) +{ + RO_PUMP_STATE_T result = RO_PUMP_CONTROL_TO_TARGET_STATE; + + // Control at set interval + if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL && roPumpControlModeSet == PUMP_CONTROL_MODE_CLOSED_LOOP ) + { + // Get the pressure to use it for setting the control + F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); + + roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP, getTargetROPumpPressure(), actualPressure ); + setROPumpControlSignalDutyCycle( roPumpDutyCyclePctSet ); + + roControlTimerCounter = 0; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The handleROPumpOpenLoopState function handles the open loop state of + * the RO pump controller state machine. + * @details Inputs: none + * @details Outputs: none + * @return next state of the controller state machine + *************************************************************************/ +static RO_PUMP_STATE_T handleROPumpOpenLoopState( void ) +{ + return RO_PUMP_OPEN_LOOP_STATE; +} + +/*********************************************************************//** + * @brief + * The setROPumpControlSignalDutyCycle function sets the duty cycle for the + * RO pump to a given duty cycle. + * @details Inputs: none + * @details Outputs: none + * @param dutyCycle which is the duty cycle + * @return none + *************************************************************************/ +static void setROPumpControlSignalDutyCycle( F32 dutyCycle ) +{ + etpwmSetCmpB( etpwmREG2, (U32)( (S32)( ( dutyCycle * (F32)(etpwmREG2->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); +} + +/*********************************************************************//** + * @brief + * The stopROPump function sets the RO pump duty cycle to zero. + * @details Inputs: isROPumpOn, roPumpPWMDutyCyclePctSet + * @details Outputs: isROPumpOn, roPumpPWMDutyCyclePctSet + * @return none + *************************************************************************/ +static void stopROPump( void ) +{ + isROPumpOn = FALSE; + roPumpDutyCyclePctSet = 0.0; + etpwmSetCmpB( etpwmREG2, 0 ); +} + +/*********************************************************************//** + * @brief + * The getPublishROPumpDataInterval function gets the RO pump data publish + * interval. + * @details Inputs: roPumpDataPublishInterval + * @details Outputs: roPumpDataPublishInterval + * @return the current RO pump data publication interval (in ms). + *************************************************************************/ +static U32 getPublishROPumpDataInterval( void ) +{ + U32 result = roPumpDataPublishInterval.data; + + if ( OVERRIDE_KEY == roPumpDataPublishInterval.override ) + { + result = roPumpDataPublishInterval.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTargetROPumpFlowRate function gets the current target RO pump + * flow rate. + * @details Inputs: targetROPumpFlowRate + * @details Outputs: targetROPumpFlowRate + * @return the current target RO flow rate (in L/min). + *************************************************************************/ +F32 getTargetROPumpFlowRate( void ) +{ + return targetROPumpFlowRate; +} + +/*********************************************************************//** + * @brief + * The getMeasuredROFlowRate function gets the measured RO pump flow rate. + * @details Inputs: measuredROFlowRateLPM + * @details Outputs: measuredROFlowRateLPM + * @return the current RO pump flow rate (in L/min). + *************************************************************************/ +F32 getMeasuredROFlowRate( void ) +{ + F32 result = measuredROFlowRateLPM.data; + + if ( OVERRIDE_KEY == measuredROFlowRateLPM.override ) + { + result = measuredROFlowRateLPM.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The getTargetROPumpPressure function gets the current target RO pump + * pressure. + * @details Inputs: targetROPumpPressure + * @details Outputs: targetROPumpPressure + * @return the current target RO targetROPumpPressure in psi. + *************************************************************************/ +F32 getTargetROPumpPressure( void ) +{ + return targetROPumpPressure; +} + +/*********************************************************************//** + * @brief + * The publishROPumpData function publishes RO pump data at the set interval. + * @details Inputs: roPumpDataPublicationTimerCounter + * @details Outputs: roPumpDataPublicationTimerCounter + * @return none + *************************************************************************/ +static void publishROPumpData( void ) +{ + // publish RO pump data on interval + if ( ++roPumpDataPublicationTimerCounter >= getPublishROPumpDataInterval() ) + { + RO_PUMP_DATA_T pumpData; + + pumpData.roPumpTgtPressure = getTargetROPumpPressure(); + pumpData.measROFlowRate = getMeasuredROFlowRate(); + pumpData.roPumpDutyCycle = roPumpDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; + pumpData.roPumpState = (U32)roPumpState; + + broadcastROPumpData( &pumpData ); + roPumpDataPublicationTimerCounter = 0; + } +} + +/************************************************************************* + * TEST SUPPORT FUNCTIONS + *************************************************************************/ + + +/*********************************************************************//** + * @brief + * The testSetROPumpDataPublishIntervalOverride function overrides the + * RO pump data publish interval. + * @details Inputs: roPumpDataPublishInterval + * @details Outputs: roPumpDataPublishInterval + * @param: value : override RO pump data publish interval with (in ms) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetROPumpDataPublishIntervalOverride( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + U32 intvl = value / TASK_PRIORITY_INTERVAL; + roPumpDataPublishInterval.ovData = intvl; + roPumpDataPublishInterval.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetROPumpDataPublishIntervalOverride function resets the + * override of the RO pump data publish interval. + * @details Inputs: roPumpDataPublishInterval + * @details Outputs: roPumpDataPublishInterval + * @return TRUE if override reset successful, FALSE if not + *************************************************************************/ +BOOL testResetROPumpDataPublishIntervalOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + roPumpDataPublishInterval.override = OVERRIDE_RESET; + roPumpDataPublishInterval.ovData = roPumpDataPublishInterval.ovInitData; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetTargetROPumpFlow function overrides the target flow rate. + * @details Inputs: none + * @details Outputs: none + * @param value which is override target RO flow rate (in L/min) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetROPumpFlow( F32 flow ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + // The flow rate and pressure must be in range + if ( flow < MAX_RO_FLOWRATE_LPM && flow >= MIN_RO_FLOWRATE_LPM ) + { + result = setROPumpTargetFlowRate( flow, MAX_ALLOWED_PRESSURE_PSI ); + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetTargetROPumpPressureOverride function overrides the target + * RO pressure. + * @details Inputs: targetROPumpPressure + * @details Outputs: targetROPumpPressure + * @param value override target RO pressure (in psi) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetROPumpPressure( U32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + // Make sure the requested pressure is in range + if ( value >= MIN_ALLOWED_PRESSURE_PSI && value <= MAX_ALLOWED_PRESSURE_PSI ) + { + targetROPumpPressure = value; + result = TRUE; + } + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetMeasuredROFlowRateOverride function overrides the measured + * RO flow rate. + * @details Inputs: measuredROFlowRateLPM + * @details Outputs: measuredROFlowRateLPM + * @param: value : override measured RO pump motor speed (in L/min) + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetMeasuredROFlowRateOverride( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + measuredROFlowRateLPM.ovInitData = measuredROFlowRateLPM.data; + measuredROFlowRateLPM.ovData = value; + measuredROFlowRateLPM.override = OVERRIDE_KEY; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testResetMeasuredROFlowRateOverride function resets the override + * of the measured RO flow rate. + * @details Inputs: measuredROFlowRateLPM + * @details Outputs: measuredROFlowRateLPM + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testResetMeasuredROFlowRateOverride( void ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + measuredROFlowRateLPM.data = measuredROFlowRateLPM.ovInitData; + measuredROFlowRateLPM.override = OVERRIDE_RESET; + measuredROFlowRateLPM.ovInitData = 0.0; + measuredROFlowRateLPM.ovData = 0.0; + result = TRUE; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The testSetTargetDutyCycleOverride function overrides the target duty + * cycle of the RO pump. + * @details Inputs: none + * @details Outputs: none + * @param value which is the duty cycle to be set + * @return TRUE if override successful, FALSE if not + *************************************************************************/ +BOOL testSetTargetDutyCycle( F32 value ) +{ + BOOL result = FALSE; + + if ( TRUE == isTestingActivated() ) + { + // Check if duty cycle is within range + if ( value >= MIN_RO_PUMP_DUTY_CYCLE && value <= MAX_RO_PUMP_DUTY_CYCLE ) + { + setROPumpTargetDutyCycle( value ); + result = TRUE; + } + } + + return result; +} + /**@}*/