/**********************************************************************//** * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file Heaters.c * * @date 21-Apr-2020 * @author Dara Navaei * * @brief DG heaters controller * **************************************************************************/ #include "etpwm.h" // TODO for testing only remove #include "mibspi.h" // TODO for testing only remove #include "AlarmMgmt.h" #include "Common.h" #include "Heaters.h" #include "TemperatureSensors.h" #include "SystemCommMessages.h" #include "PIControllers.h" #define MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE 0.89 ///< Main primary heater (heater A) max duty cycle (79.5%) #define SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE 0.50 ///< Small Primary heater (heater B) max duty cycle (25%) #define TRIMMER_HEATER_MAX_DUTY_CYCLE 0.50 ///< Trimmer heater max duty cycle (25%) #define HEATERS_MIN_DUTY_CYCLE 0.00 ///< Primary and trimmer heaters minimum duty cycle (0.00%) #define PRIMARY_HEATERS_P_COEFFICIENT 0.02 ///< Primary heaters proportional coefficient #define PRIMARY_HEATERS_I_COEFFICIENT 0.001 ///< Primary heaters integral coefficient #define TRIMMER_HEATER_P_COEFFICIENT 0.02 ///< Trimmer heater proportional coefficient #define TRIMMER_HEATER_I_COEFFICIENT 0.001 ///< Trimmer heater integral coefficient #define DELTA_TEMP_TO_PWM_DUTY_CYCLE_CONVERSION 0.05 ///< Delta temperature to PWM duty cycle conversion (initial guess) #define CONTROLLER_CHECK_INTERVAL_COUNT 10U ///< Time interval count to check the PI controller #define TEMP_SENSORS_INTERVAL_COUNT 10U ///< Temperature sensors interval count /// Heaters self test enums typedef enum heaters_self_test_states { HEATERS_SELF_TEST_START = 0, ///< Heaters self test start state HEATERS_SELF_TEST_START_SMALL_PRIMARY_AND_TRIMMER, ///< Heaters self test small primary and trimmer heaters state HEATERS_SELF_TEST_START_MAIN_PRIMARY, ///< Heaters self test start main primary state HEATERS_SELF_TEST_COMPLETE, ///< Heaters self test complete state NUM_OF_HEATERS_SELF_TEST_STATES ///< Number of heaters self test states } HEATERS_SELF_TEST_STATES_T ; /// Primary heaters exec states typedef enum primary_heaters_exec_states { PRIMARY_HEATERS_EXEC_STATE_OFF = 0, ///< Primary heaters exec state off PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET, ///< Primary heaters exec state control to target (PI controller state) NUM_OF_PRIMARY_HEATERS_EXEC_STATES ///< Number of primary heaters exec states } PRIMARY_HEATERS_EXEC_STATES_T; /// Trimmer heater exec states typedef enum trimmer_heater_exec_states { TRIMMER_HEATER_EXEC_STATE_OFF = 0, ///< Trimmer heater exec state off TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET, ///< Trimmer heater exec state control to target (PI controller state) NUM_OF_TRIMMER_HEATER_EXEC_STATES ///< Number of trimmer heater exec states } TRIMMER_HEATER_EXEC_STATES_T; /// Name of the heaters states typedef enum name_of_heaters { PRIMARY_HEATER = 0, ///< Primary heater TRIMMER_HEATER, ///< Trimmer heater NUM_OF_HEATERS ///< Number of heaters } NAME_OF_HEATER_T; // Private variables static SELF_TEST_STATUS_T heatersSelfTestResult; ///< Heaters self test results static HEATERS_SELF_TEST_STATES_T heatersSelfTestState; ///< Heaters self test state static PRIMARY_HEATERS_EXEC_STATES_T primaryHeatersExecState; ///< Primary heaters exec state static TRIMMER_HEATER_EXEC_STATES_T trimmerHeaterExecState; ///< Trimmer heater exec state static F32 primaryHeaterTargetTemperature; ///< Primary heaters target temperature static F32 trimmerHeaterTargetTemperature; ///< Trimmer heater target temperature static F32 mainPrimaryHeaterDutyCycle; ///< Main primary heater duty cycle static F32 smallPrimaryHeaterDutyCycle; ///< Small primary heater duty cycle static F32 trimmerHeaterDutyCycle; ///< Trimmer heater duty cycle static U32 primaryHeaterTimerCounter; ///< Primary heater timer counter static U32 trimmerHeaterTimerCounter; ///< Trimmer heater timer counter static U32 dataPublicationTimerCounter; ///< Data publication timer counter // private functions prototypes static PRIMARY_HEATERS_EXEC_STATES_T handlePrimaryHeaterStateOff ( void ); static PRIMARY_HEATERS_EXEC_STATES_T handlePrimaryHeaterStateControlToTarget ( void ); static TRIMMER_HEATER_EXEC_STATES_T handleTrimmerHeaterStateOff ( void ); static TRIMMER_HEATER_EXEC_STATES_T handleTrimmerHeaterControlToTarget ( void ); static void setMainPrimaryHeaterPWM ( F32 pwm ); static void setSmallPrimaryHeaterPWM ( F32 pwm ); static void setTrimmerHeaterPWM ( F32 pwm ); static void resetHeaterState ( NAME_OF_HEATER_T heater ); static void publishTemperatureData ( void ); // TODO: Remove the below code. FOR TESTING ONLY #define PRIMARY_HEATER_MIBSPI1_PORT_MASK 0x00000002 // (CS1 - re-purposed as input GPIO) #define TOGGLEPRIMAYHEATER() (( mibspiREG1->PC2 & PRIMARY_HEATER_MIBSPI1_PORT_MASK ) != 0) //TODO: Remove the above code. FOR TESTING ONLY // Public functions /*********************************************************************//** * @brief initHeaters * The initHeaters function initializes the variables. * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ void initHeaters ( void ) { heatersSelfTestResult = SELF_TEST_STATUS_IN_PROGRESS; 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; // initialize the PI controller for the primary heaters initializePIController( PI_CONTROLLER_ID_PRIMARY_HEATER, HEATERS_MIN_DUTY_CYCLE, PRIMARY_HEATERS_P_COEFFICIENT, PRIMARY_HEATERS_I_COEFFICIENT, HEATERS_MIN_DUTY_CYCLE, MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE + SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE ); // initialize the PI controller for the trimmer heater initializePIController( PI_CONTROLLER_ID_TRIMMER_HEATER, HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_P_COEFFICIENT, TRIMMER_HEATER_I_COEFFICIENT, HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_MAX_DUTY_CYCLE ); } /*********************************************************************//** * @brief setPrimaryHeaterTargetTemperature * The setPrimaryHeaterTargetTemperature function sets the primary heater * target temperature * @details * Inputs : F32 (targetTemp) * Outputs : none * @return none *************************************************************************/ void setPrimaryHeaterTargetTemperature ( F32 targetTemp ) { primaryHeaterTargetTemperature = targetTemp; } /*********************************************************************//** * @brief setTrimmerHeaterTargetTemperature * The setTrimmerHeaterTargetTemperature function sets the trimmer heater * target temperature * @details * Inputs : F32 (targetTemp) * Outputs : none * @return none *************************************************************************/ void setTrimmerHeaterTargetTemperature ( F32 targetTemp ) { trimmerHeaterTargetTemperature = targetTemp; } /*********************************************************************//** * @brief startPrimaryHeater * The startPrimaryHeater function starts the primary heaters * @details * Inputs : none * Outputs : BOOL (status) * @return BOOL (status) *************************************************************************/ BOOL startPrimaryHeater ( void ) { BOOL status = FALSE; if ( primaryHeaterTargetTemperature != 0.0 ) { resetHeaterState ( PRIMARY_HEATER ); setMainPrimaryHeaterPWM ( mainPrimaryHeaterDutyCycle ); primaryHeatersExecState = PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET; status = TRUE; } return status; } /*********************************************************************//** * @brief startTrimmerHeater * The startTrimmerHeater function starts the trimmer heater * @details * Inputs : none * Outputs : BOOL (status) * @return BOOL (status) *************************************************************************/ BOOL startTrimmerHeater ( void ) { BOOL status = FALSE; if ( trimmerHeaterTargetTemperature != 0.0 ) { resetHeaterState ( TRIMMER_HEATER ); setTrimmerHeaterPWM ( trimmerHeaterDutyCycle ); trimmerHeaterExecState = TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET; status = TRUE; } return status; } /*********************************************************************//** * @brief stopPrimaryHeater * The stopPrimaryHeater function stops the primary heaters * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ void stopPrimaryHeater ( void ) { setMainPrimaryHeaterPWM ( HEATERS_MIN_DUTY_CYCLE ); setSmallPrimaryHeaterPWM ( HEATERS_MIN_DUTY_CYCLE ); primaryHeatersExecState = PRIMARY_HEATERS_EXEC_STATE_OFF; } /*********************************************************************//** * @brief stopTrimmerHeater * The stopTrimmerHeater function stops the trimmer heater * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ void stopTrimmerHeater ( void ) { setTrimmerHeaterPWM ( HEATERS_MIN_DUTY_CYCLE ); } /*********************************************************************//** * @brief execHeatersMonitor * The execHeatersMonitor function * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ void execHeatersMonitor ( void ) { // TODO Decide the parts of this function } /*********************************************************************//** * @brief execHeatersSelfTest * The execHeatersSelfTest function executes the heaters self test * @details * Inputs : none * Outputs : SELF_TEST_STATUS_T * @return SELF_TEST_STATUS_T *************************************************************************/ SELF_TEST_STATUS_T execHeatersSelfTest ( void ) { switch ( heatersSelfTestState ) { case HEATERS_SELF_TEST_START: break; case HEATERS_SELF_TEST_START_SMALL_PRIMARY_AND_TRIMMER: break; case HEATERS_SELF_TEST_START_MAIN_PRIMARY: break; case HEATERS_SELF_TEST_COMPLETE: break; default: SET_ALARM_WITH_2_U32_DATA ( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_SELF_TEST_INVALID_STATE, heatersSelfTestState ); heatersSelfTestState = HEATERS_SELF_TEST_COMPLETE; break; } return heatersSelfTestResult; } /*********************************************************************//** * @brief execPrimaryHeaters * The execPrimaryHeaters function executes the primary heaters * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ void execPrimaryHeaters ( void ) { switch ( primaryHeatersExecState ) { case PRIMARY_HEATERS_EXEC_STATE_OFF: primaryHeatersExecState = handlePrimaryHeaterStateOff(); break; case PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET: primaryHeatersExecState = handlePrimaryHeaterStateControlToTarget(); break; default: SET_ALARM_WITH_2_U32_DATA ( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_PRIMARY_HEATER_EXEC_INVALID_STATE, primaryHeatersExecState ); primaryHeatersExecState = PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET; break; } } /*********************************************************************//** * @brief execTrimmerHeater * The execTrimmerHeater function executes the trimmer heater * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ void execTrimmerHeater ( void ) { switch ( trimmerHeaterExecState ) { case TRIMMER_HEATER_EXEC_STATE_OFF: trimmerHeaterExecState = handleTrimmerHeaterStateOff(); break; case TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET: trimmerHeaterExecState = handleTrimmerHeaterControlToTarget(); break; default: SET_ALARM_WITH_2_U32_DATA ( ALARM_ID_SOFTWARE_FAULT, SW_FAULT_ID_HEATERS_TRIMMER_HEATER_EXEC_INVALID_STATE, trimmerHeaterExecState ); trimmerHeaterExecState = TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET; break; } } // Private functions /*********************************************************************//** * @brief handlePrimaryHeaterStateOff * The handlePrimaryHeaterStateOff function handles the primary heaters at * off state * @details * Inputs : none * Outputs : PRIMARY_HEATERS_EXEC_STATES_T (state) * @return PRIMARY_HEATERS_EXEC_STATES_T (state) *************************************************************************/ static PRIMARY_HEATERS_EXEC_STATES_T handlePrimaryHeaterStateOff ( void ) { PRIMARY_HEATERS_EXEC_STATES_T state = PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET; // TODO for testing only. remove state = PRIMARY_HEATERS_EXEC_STATE_OFF; if ( TOGGLEPRIMAYHEATER() ) { setPrimaryHeaterTargetTemperature ( 37 ); if ( getTemperatureValue ( TEMPSENSORS_INLET_PRIMARY_HEATER_TEMP_SENSOR ) > 0 ) { startPrimaryHeater(); state = PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET; } //state = PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET; } // TODO remove this code for testing return state; } /*********************************************************************//** * @brief handlePrimaryHeaterStateControlToTarget * The handlePrimaryHeaterStateControlToTarget function handles the primary * heaters at control state when the heaters are active * @details * Inputs : none * Outputs : PRIMARY_HEATERS_EXEC_STATES_T (state) * @return PRIMARY_HEATERS_EXEC_STATES_T (state) *************************************************************************/ static PRIMARY_HEATERS_EXEC_STATES_T handlePrimaryHeaterStateControlToTarget ( void ) { PRIMARY_HEATERS_EXEC_STATES_T state = PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET; if ( ++primaryHeaterTimerCounter >= CONTROLLER_CHECK_INTERVAL_COUNT ) { F32 outletTemp = getTemperatureValue ( TEMPSENSORS_OUTLET_PRIMARY_HEATER_TEMP_SENSOR ); mainPrimaryHeaterDutyCycle = runPIController ( PI_CONTROLLER_ID_PRIMARY_HEATER, primaryHeaterTargetTemperature, outletTemp ); if ( mainPrimaryHeaterDutyCycle >= MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE ) { 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 ); } primaryHeaterTimerCounter = 0; } publishTemperatureData(); // TODO remove this code if ( !TOGGLEPRIMAYHEATER() ) { stopPrimaryHeater(); state = PRIMARY_HEATERS_EXEC_STATE_OFF; } // TODO Remove this code return state; } /*********************************************************************//** * @brief handleTrimmerHeaterStateOff * The handleTrimmerHeaterStateOff function handles the trimmer heater at * off state * @details * Inputs : none * Outputs : TRIMMER_HEATER_EXEC_STATES_T (state) * @return TRIMMER_HEATER_EXEC_STATES_T (state) *************************************************************************/ static TRIMMER_HEATER_EXEC_STATES_T handleTrimmerHeaterStateOff ( void ) { TRIMMER_HEATER_EXEC_STATES_T state = TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET; // TODO for testing only. remove state = TRIMMER_HEATER_EXEC_STATE_OFF; if ( TOGGLEPRIMAYHEATER() ) { setTrimmerHeaterTargetTemperature ( 37 ); if ( getTemperatureValue ( TEMPSENSORS_OUTLET_REDUNDANCY_TEMP_SENSOR ) > 0 ) { startTrimmerHeater(); state = TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET; } state = TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET; } // TODO remove this code for testing return state; } /*********************************************************************//** * @brief handleTrimmerHeaterControlToTarget * The handleTrimmerHeaterControlToTarget function handles the trimmer * heater at control state when the heater is active * @details * Inputs : none * Outputs : TRIMMER_HEATER_EXEC_STATES_T (state) * @return TRIMMER_HEATER_EXEC_STATES_T (state) *************************************************************************/ static TRIMMER_HEATER_EXEC_STATES_T handleTrimmerHeaterControlToTarget ( void ) { TRIMMER_HEATER_EXEC_STATES_T state = TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET; if ( ++trimmerHeaterTimerCounter >= CONTROLLER_CHECK_INTERVAL_COUNT ) { F32 outletTemp = getTemperatureValue ( TEMPSENSORS_OUTLET_REDUNDANCY_TEMP_SENSOR ); trimmerHeaterDutyCycle = runPIController ( PI_CONTROLLER_ID_TRIMMER_HEATER, trimmerHeaterTargetTemperature, outletTemp ); setTrimmerHeaterPWM ( trimmerHeaterDutyCycle ); trimmerHeaterTimerCounter = 0; } publishTemperatureData(); // TODO remove this code if ( !TOGGLEPRIMAYHEATER() ) { stopTrimmerHeater(); state = TRIMMER_HEATER_EXEC_STATE_OFF; } // TODO Remove this code return state; } /*********************************************************************//** * @brief setMainPrimaryHeaterPWM * The setMainPrimaryHeaterPWM function sets the PWM of the main primary * heater * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ static void setMainPrimaryHeaterPWM ( F32 pwm ) { etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( pwm * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); } /*********************************************************************//** * @brief setSmallPrimaryHeaterPWM * The setSmallPrimaryHeaterPWM function sets the PWM of the small primary * heater * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ static void setSmallPrimaryHeaterPWM ( F32 pwm ) { etpwmSetCmpB( etpwmREG1, (U32)( (S32)( ( pwm * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); } /*********************************************************************//** * @brief setTrimmerHeaterPWM * The setTrimmerHeaterPWM function sets the PWM of the trimmer heater * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ static void setTrimmerHeaterPWM ( F32 pwm ) { etpwmSetCmpA( etpwmREG3, (U32)( (S32)( ( pwm * (F32)(etpwmREG3->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); } /*********************************************************************//** * @brief resetHeaterState * The resetHeaterState function resets the PI controller of the selected * heater * @details * Inputs : none * Outputs : none * @return none *************************************************************************/ static void resetHeaterState ( NAME_OF_HEATER_T heater ) { if ( heater == PRIMARY_HEATER ) { F32 inletTemperatrue = getTemperatureValue ( TEMPSENSORS_INLET_PRIMARY_HEATER_TEMP_SENSOR ); mainPrimaryHeaterDutyCycle = fabs(primaryHeaterTargetTemperature - inletTemperatrue) * DELTA_TEMP_TO_PWM_DUTY_CYCLE_CONVERSION; resetPIController ( PI_CONTROLLER_ID_PRIMARY_HEATER, mainPrimaryHeaterDutyCycle ); } else if ( heater == TRIMMER_HEATER ) { F32 inletTemperatrue = getTemperatureValue ( TEMPSENSORS_OUTLET_REDUNDANCY_TEMP_SENSOR ); trimmerHeaterDutyCycle = fabs(trimmerHeaterTargetTemperature - inletTemperatrue) * DELTA_TEMP_TO_PWM_DUTY_CYCLE_CONVERSION; resetPIController ( PI_CONTROLLER_ID_TRIMMER_HEATER, trimmerHeaterDutyCycle ); } } /************************************************************************* * @brief publishTemperatureData * The publishTemperatureData function publishes the temperature sensors * data into the USB debug port at the defined time interval * @details * Inputs : none * Outputs : none * @param none * @return none *************************************************************************/ static void publishTemperatureData ( void ) { if ( ++dataPublicationTimerCounter >= TEMP_SENSORS_INTERVAL_COUNT ) { //#ifdef DEBUG_ENABLED // { // char debugTempStr[ 256 ]; // sprintf( debugTempStr, "MPDuty: %6.2f, SPDuty: %6.2f, THDuty: %6.2f, TPi: %6.2f, TPo: %6.2f, TD1: %6.2f, " // "TD2: %6.2f, TRo: %6.2f, TDi: %6.2f, TPh: %6.2f, TTh: %6.2f, PTarg: %6.2f, TTarg: %6.2f\r\n", // mainPrimaryHeaterDutyCycle, smallPrimaryHeaterDutyCycle, trimmerHeaterDutyCycle, // getTemperatureValue ( TEMPSENSORS_INLET_PRIMARY_HEATER_TEMP_SENSOR ), // getTemperatureValue ( TEMPSENSORS_OUTLET_PRIMARY_HEATER_TEMP_SENSOR ), // getTemperatureValue ( TEMPSENSORS_CONDUCTIVITY_SENSOR_1_TEMP_SENSOR ), // getTemperatureValue ( TEMPSENSORS_CONDUCTIVITY_SENSOR_2_TEMP_SENSOR ), // getTemperatureValue ( TEMPSENSORS_OUTLET_REDUNDANCY_TEMP_SENSOR ), // getTemperatureValue ( TEMPSENSORS_INLET_DIALYSATE_TEMP_SENSOR ), // getTemperatureValue ( TEMPSENSORS_PRIMARY_HEATER_INTERNAL_TEMP_SENSOR ), // getTemperatureValue ( TEMPSENSORS_TRIMMER_HEATER_INTERNAL_TEMP_SESNOR ), // primaryHeaterTargetTemperature, trimmerHeaterTargetTemperature); // sendDebugData ( (U08*)debugTempStr, strlen(debugTempStr) ); // } //#endif dataPublicationTimerCounter = 0; } }