Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r0c296cef29037819be204c45a23d4d38a52b2718 -r8e0041d52daf1dc3596ecef18b4ab58b9b4818a6 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 0c296cef29037819be204c45a23d4d38a52b2718) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 8e0041d52daf1dc3596ecef18b4ab58b9b4818a6) @@ -7,8 +7,8 @@ * * @file Heaters.c * -* @author (last) Dara Navaei -* @date (last) 18-Oct-2022 +* @author (last) Bill Bracken +* @date (last) 25-Oct-2022 * * @author (original) Dara Navaei * @date (original) 23-Apr-2020 @@ -38,6 +38,7 @@ #include "TaskPriority.h" #include "TemperatureSensors.h" #include "Timers.h" +#include "Utilities.h" #include "Voltages.h" /** @@ -49,7 +50,7 @@ #define HEATERS_MAX_DUTY_CYCLE 1.00F ///< Heaters max duty cycle (100%). #define HEATERS_MIN_DUTY_CYCLE 0.00F ///< Heaters minimum duty cycle (0.00%). -#define HEATERS_DISINFECT_DUTY_CYCLE 0.70F ///< Heaters disinfect cycle. +#define HEATERS_DISINFECT_DUTY_CYCLE 0.80F ///< Heaters disinfect cycle. #define HEATERS_DISINFECT_TEMPERATURE_DRIFT_C 3.0F ///< Heaters disinfect temperature drift in C. #define HEATERS_MIN_EST_GAIN 0.2F ///< Heaters minimum estimation gain. #define HEATERS_MAX_EST_GAIN 5.0F ///< Heaters maximum estimation gain. @@ -65,7 +66,8 @@ #define HEATERS_VOLTAGE_OUT_OF_RANGE_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Heaters voltage out of range time out in milliseconds. #define HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL 0.2F ///< Heaters max voltage out of range tolerance. #define TRIMMER_HEATER_MAX_POWER_W 66.5F ///< Trimmer heater maximum power in Watts. -#define HEATER_CONTROL_CHECK_INTERVAL_COUNT ( ( 30 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Heater control interval count. +#define TRIMMER_HEATER_INITIAL_CONTROL_INTERVAL_COUNT ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Trimmer heater initial control interval count. +#define TRIMMER_HEATER_CONTROL_INTERVAL_COUNT ( ( 30 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Trimmer heater control interval count. #define DELTA_TEMPERATURE_TIME_COSNTANT_C 8.6F ///< Delta temperature calculated from time constant. #define PRIMARY_HEATER_DUTY_CYCLE_PER_TEMPERATURE_C 0.015F ///< Primary heaters duty cycle per temperature in C. @@ -90,14 +92,15 @@ F32 targetFlow; ///< Heater target flow. BOOL hasTargetTempChanged; ///< Heater target temperature change flag indicator. F32 heaterEstGain; ///< Heater estimation gain during the run. - BOOL hasTargetBeenReached; ///< Heater flag to indicate whether the target temperature has been reached. F32 calculatedTemperature; ///< Heater calculated temperature. DG_RESERVOIR_ID_T inactiveRsrvr; ///< Heater inactive reservoir. + U32 controlIntervalCounter; ///< Heater control interval counter. + BOOL isThisFirstControl; ///< Heater is this first control interval. + BOOL useLastDutyCycle; ///< Heater has use previous duty cycle been requested flag. } HEATER_STATUS_T; static HEATER_STATUS_T heatersStatus[ NUM_OF_DG_HEATERS ]; ///< Heaters status. static U32 dataPublicationTimerCounter; ///< Data publication timer counter. -static U32 heaterControlCounter; ///< Heater control counter. static OVERRIDE_U32_T heatersDataPublishInterval = { HEATERS_DATA_PUBLISH_INTERVAL, HEATERS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Heaters data publish time interval. // ********** private function prototypes ********** @@ -124,28 +127,28 @@ * @brief * The initHeaters initializes the heaters driver. * @details Inputs: none - * @details Outputs: voltageMonitorTimeCounter, heaterStatus, - * hasTreatmentInternalTempBeenSet, dataPublicationTimerCounter, - * trimmerHeaterControlCounter + * @details Outputs: heaterStatus, + * dataPublicationTimerCounter * @return none *************************************************************************/ void initHeaters( void ) { DG_HEATERS_T heater; dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; - heaterControlCounter = 0; for ( heater = DG_PRIMARY_HEATER; heater < NUM_OF_DG_HEATERS; heater++ ) { - heatersStatus[ heater ].targetTemp = 0.0F; - heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; - heatersStatus[ heater ].startHeaterSignal = FALSE; - heatersStatus[ heater ].isHeaterOn = FALSE; - heatersStatus[ heater ].dutyCycle = 0.0F; - heatersStatus[ heater ].targetFlow = 0.0F; - heatersStatus[ heater ].hasTargetTempChanged = FALSE; - heatersStatus[ heater ].heaterEstGain = HEATERS_NEUTRAL_EST_GAIN; - heatersStatus[ heater ].hasTargetBeenReached = FALSE; + heatersStatus[ heater ].targetTemp = 0.0F; + heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; + heatersStatus[ heater ].startHeaterSignal = FALSE; + heatersStatus[ heater ].isHeaterOn = FALSE; + heatersStatus[ heater ].dutyCycle = 0.0F; + heatersStatus[ heater ].targetFlow = 0.0F; + heatersStatus[ heater ].hasTargetTempChanged = FALSE; + heatersStatus[ heater ].heaterEstGain = HEATERS_NEUTRAL_EST_GAIN; + heatersStatus[ heater ].controlIntervalCounter = 0; + heatersStatus[ heater ].isThisFirstControl = TRUE; + heatersStatus[ heater ].useLastDutyCycle = FALSE; } // Initialize the persistent alarms @@ -438,6 +441,20 @@ /*********************************************************************//** * @brief + * The setTrimmerHeaterUseLastDutyCycleStatus function sets the flag that + * signals the trimmer heater control to use the last duty cycle or not + * @details Inputs: none + * @details Outputs: heatersStatus + * @param status which is the flag to indicate the status + * @return none + *************************************************************************/ +void setTrimmerHeaterUseLastDutyCycleStatus( BOOL status ) +{ + heatersStatus[ DG_TRIMMER_HEATER ].useLastDutyCycle = status; +} + +/*********************************************************************//** + * @brief * The handleHeaterStateOff function handles the heater not running state. * @details Inputs: heaterStatus * @details Outputs: heaterStatus @@ -534,7 +551,20 @@ { state = HEATER_EXEC_STATE_PRIMARY_RAMP_TO_TARGET; } + else if ( TRUE == heatersStatus[ heater ].hasTargetTempChanged ) + { + F32 inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); + F32 targetTemperature = heatersStatus[ heater ].targetTemp; + F32 targetFlow = getTargetROPumpFlowRateLPM(); + F32 dutyCycle = calculatePrimaryHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow, TRUE ); + heatersStatus[ heater ].calculatedTemperature = targetTemperature; + heatersStatus[ heater ].targetFlow = targetFlow; + heatersStatus[ heater ].hasTargetTempChanged = FALSE; + + setHeaterDutyCycle( heater, dutyCycle ); + } + return state; } @@ -593,9 +623,17 @@ if ( ( DG_MODE_FILL == opMode ) || ( DG_MODE_GENE == opMode ) || ( DG_MODE_DRAI == opMode ) ) { - currentTemperature = getReservoirCurrentTemperature(); - dutyCycle = calculateTrimmerHeaterDutyCycle( targetTemperature, currentTemperature, targetFlowLPM, TRUE ); - state = HEATER_EXEC_STATE_TRIMMER_CONTROL_TO_TARGET; + if ( FALSE == heatersStatus[ heater ].useLastDutyCycle ) + { + currentTemperature = getReservoirCurrentTemperature(); + dutyCycle = calculateTrimmerHeaterDutyCycle( targetTemperature, currentTemperature, targetFlowLPM, TRUE ); + } + else + { + dutyCycle = heatersStatus[ heater ].dutyCycle; + } + + state = HEATER_EXEC_STATE_TRIMMER_CONTROL_TO_TARGET; } else if ( DG_MODE_HEAT == opMode ) { @@ -620,7 +658,7 @@ heatersStatus[ heater ].calculatedTemperature = currentTemperature; heatersStatus[ heater ].inactiveRsrvr = getInactiveReservoir(); heatersStatus[ heater ].targetFlow = targetFlowLPM; - heaterControlCounter = 0; + heatersStatus[ heater ].isThisFirstControl = TRUE; // Cap the minimum duty cycle. So if it is calculated to negative, set it to 0 dutyCycle = MAX( dutyCycle, HEATERS_MIN_DUTY_CYCLE ); @@ -641,28 +679,34 @@ { HEATERS_STATE_T state = HEATER_EXEC_STATE_TRIMMER_CONTROL_TO_TARGET; F32 tempDutyCycle = 0.0F; + DG_HEATERS_T heater = DG_TRIMMER_HEATER; + U32 controlInterval = ( TRUE == heatersStatus[ heater ].isThisFirstControl ? TRIMMER_HEATER_INITIAL_CONTROL_INTERVAL_COUNT : + TRIMMER_HEATER_CONTROL_INTERVAL_COUNT ); // If the inactive reservoir has changed from the last run transition to ramp state to recalculate the // duty cycle for the next delivery - if ( heatersStatus[ DG_TRIMMER_HEATER ].inactiveRsrvr != getInactiveReservoir() ) + if ( heatersStatus[ heater ].inactiveRsrvr != getInactiveReservoir() ) { state = HEATER_EXEC_STATE_TRIMMER_RAMP_TO_TARGET; } - else if ( ++heaterControlCounter > HEATER_CONTROL_CHECK_INTERVAL_COUNT ) + else if ( ++heatersStatus[ heater ].controlIntervalCounter > controlInterval ) { + // Reset the control counter + heatersStatus[ heater ].controlIntervalCounter = 0; + heatersStatus[ heater ].isThisFirstControl = FALSE; + // When the trimmer heater is on, its duty cycle is adjusted at the control interval. For this control check, // dialysate inlet temperature sensor is used rather than the theoretical calculations. F32 outletRedundantTemperature = getTemperatureValue( TEMPSENSORS_OUTLET_REDUNDANT ); - F32 targetTemperature = heatersStatus[ DG_TRIMMER_HEATER ].targetTemp; - F32 targetFlowLPM = heatersStatus[ DG_TRIMMER_HEATER ].targetFlow; + F32 targetTemperature = heatersStatus[ heater ].targetTemp; + F32 targetFlowLPM = heatersStatus[ heater ].targetFlow; F32 dutyCycle = calculateTrimmerHeaterDutyCycle( targetTemperature, outletRedundantTemperature, targetFlowLPM, TRUE ); - heaterControlCounter = 0; - tempDutyCycle = heatersStatus[ DG_TRIMMER_HEATER ].dutyCycle + dutyCycle; + tempDutyCycle = heatersStatus[ heater ].dutyCycle + dutyCycle; tempDutyCycle = MIN( tempDutyCycle, HEATERS_MAX_DUTY_CYCLE ); tempDutyCycle = MAX( tempDutyCycle, HEATERS_MIN_DUTY_CYCLE ); - setHeaterDutyCycle( DG_TRIMMER_HEATER, tempDutyCycle ); + setHeaterDutyCycle( heater, tempDutyCycle ); } return state; @@ -776,11 +820,10 @@ BOOL hasFlowChanged = ( fabs( targetFlow - heatersStatus[ heater ].targetFlow ) > NEARLY_ZERO ? TRUE : FALSE ); // Check if the target flow has changed or the target temperature has changed. - if ( ( TRUE == hasFlowChanged ) || ( TRUE == heatersStatus[ heater ].hasTargetTempChanged ) ) + if ( TRUE == hasFlowChanged ) { - status = TRUE; - heatersStatus[ heater ].targetFlow = targetFlow; - heatersStatus[ heater ].hasTargetTempChanged = FALSE; + status = TRUE; + heatersStatus[ heater ].targetFlow = targetFlow; } return status; @@ -875,6 +918,7 @@ data.primaryEfficiency = heatersStatus[ DG_PRIMARY_HEATER ].heaterEstGain * FRACTION_TO_PERCENT_FACTOR; data.primaryCalcTargetTemp = heatersStatus[ DG_PRIMARY_HEATER ].calculatedTemperature; data.trimmerCalcCurrentTemp = heatersStatus[ DG_TRIMMER_HEATER ].calculatedTemperature; + data.trimmerUseLastDC = (U32)heatersStatus[ DG_TRIMMER_HEATER ].useLastDutyCycle; dataPublicationTimerCounter = 0; broadcastData( MSG_ID_DG_HEATERS_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( HEATERS_DATA_T ) ); @@ -884,8 +928,8 @@ /*********************************************************************//** * @brief * The monitorHeatersVoltage function monitors the heaters' voltages - * @details Inputs: voltageMonitorTimeCounter - * @details Outputs: voltageMonitorTimeCounter + * @details Inputs: none + * @details Outputs: none * @return none *************************************************************************/ static void monitorHeatersVoltage( void ) @@ -909,7 +953,7 @@ BOOL isTrimmerOut = FALSE; #ifndef _RELEASE_ - if ( SW_CONFIG_ENABLE_VALUE == getSoftwareConfigStatus( SW_CONFIG_ENABLE_V3_SYSTEM ) ) + if ( HW_CONFIG_BETA == getHardwareConfigStatus() ) { // V3 use CPU based value for Primary, same as Secondary mainPriVoltage = getMonitoredLineLevel( MONITORED_LINE_24V_GND_SMALL_PRIM_HTR_V ); @@ -933,7 +977,7 @@ checkPersistentAlarm( ALARM_ID_DG_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE, isTrimmerOut, trimmerDC, HEATERS_VOLTAGE_TOLERANCE_V ); #ifndef _RELEASE_ - if ( SW_CONFIG_ENABLE_VALUE != getSoftwareConfigStatus( SW_CONFIG_ENABLE_V3_SYSTEM ) ) + if ( getHardwareConfigStatus() != HW_CONFIG_BETA ) #endif { // If the system is DVT, check the primary heater's power line voltage