Index: firmware/App/Controllers/DialInFlow.c =================================================================== diff -u -rabbad386f4cc94f315300dffef321fe8c03fbd52 -r8466e63f95f65a3ffb18c3af85ac99328e41167b --- firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision abbad386f4cc94f315300dffef321fe8c03fbd52) +++ firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 8466e63f95f65a3ffb18c3af85ac99328e41167b) @@ -42,17 +42,18 @@ // ********** private definitions ********** /// Interval (ms/task time) at which the dialIn flow data is published on the CAN bus. -#define DIAL_IN_FLOW_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) +#define DIAL_IN_FLOW_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) -#define MAX_DIAL_IN_PUMP_PWM_STEP_UP_CHANGE 0.0133 ///< Max duty cycle change when ramping up ~ 200 mL/min/s. -#define MAX_DIAL_IN_PUMP_PWM_STEP_DN_CHANGE 0.02 ///< Max duty cycle change when ramping down ~ 300 mL/min/s. -#define MAX_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.89 ///< Controller will error if PWM duty cycle > 90%, so set max to 89%. -#define MIN_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.10 ///< Controller will error if PWM duty cycle < 10%, so set min to 10%. +#define MAX_DIAL_IN_PUMP_PWM_STEP_UP_CHANGE 0.0133 ///< Max duty cycle change when ramping up ~ 200 mL/min/s. +#define MAX_DIAL_IN_PUMP_PWM_STEP_DN_CHANGE 0.02 ///< Max duty cycle change when ramping down ~ 300 mL/min/s. +#define MAX_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.89 ///< Controller will error if PWM duty cycle > 90%, so set max to 89%. +#define MIN_DIAL_IN_PUMP_PWM_DUTY_CYCLE 0.10 ///< Controller will error if PWM duty cycle < 10%, so set min to 10%. +#define DIP_CONTROL_INTERVAL_SEC 10 ///< Dialysate inlet pump control interval (in seconds). /// Interval (ms/task time) at which the dialIn pump is controlled. -static const U32 DIP_CONTROL_INTERVAL = ( 10000 / TASK_GENERAL_INTERVAL ); -#define DIP_P_COEFFICIENT 0.00035 ///< P term for dialIn pump control. -#define DIP_I_COEFFICIENT 0.00035 ///< I term for dialIn pump control. +static const U32 DIP_CONTROL_INTERVAL = ( DIP_CONTROL_INTERVAL_SEC * MS_PER_SECOND / TASK_GENERAL_INTERVAL ); +#define DIP_P_COEFFICIENT 0.0001 ///< P term for dialIn pump control. +#define DIP_I_COEFFICIENT 0.00075 ///< I term for dialIn pump control. #define DIP_HOME_RATE 100 ///< Target pump speed (in estimate mL/min) for homing. #define DIP_HOME_TIMEOUT_MS 10000 ///< Maximum time allowed for homing to complete (in ms). @@ -62,6 +63,8 @@ #define DIP_SPEED_CALC_BUFFER_LEN ( 1000 / DIP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) #define DIP_HALL_EDGE_COUNTS_PER_REV 48 ///< Number of hall sensor edge counts per motor revolution. +#define DIP_MAX_FLOW_RATE 1320.0 ///< Maximum measured BP flow rate allowed. +#define DIP_MIN_FLOW_RATE -1320.0 ///< Minimum measured BP flow rate allowed. #define DIP_MAX_FLOW_VS_SPEED_DIFF_RPM 200.0 ///< Maximum difference between measured motor speed and speed implied by measured flow. #define DIP_MAX_MOTOR_SPEED_WHILE_OFF_RPM 100.0 ///< Maximum motor speed (RPM) while motor is commanded off. #define DIP_MAX_ROTOR_VS_MOTOR_DIFF_RPM 5.0 ///< Maximum difference in speed between motor and rotor (in rotor RPM). @@ -77,19 +80,15 @@ static const U32 DIP_ROTOR_SPEED_ERROR_PERSIST = ((12 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); /// Persist time (task intervals) pump direction error condition. static const U32 DIP_DIRECTION_ERROR_PERSIST = (250 / TASK_PRIORITY_INTERVAL); +/// Persist time (task intervals) dialysate flow rate out of range error condition. +static const U32 DIP_MAX_FLOW_RATE_OUT_OF_RANGE_PERSIST = ((1 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); - #define DIP_MAX_CURR_WHEN_STOPPED_MA 150.0 ///< Motor controller current should not exceed this when pump should be stopped. #define DIP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running. #define DIP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. -#ifndef V2_0_SYSTEM - #define DIP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialIn pump motor. - #define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00025 ///< ~40 BP motor RPM = 1% PWM duty cycle -#else - #define DIP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for blood pump motor - #define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003125 ///< ~32 BP motor RPM = 1% PWM duty cycle -#endif +#define DIP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialIn pump motor. +#define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000193 ///< ~52 BP motor RPM = 1% PWM duty cycle #define DIP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for dialIn pump motor. #define DIP_REV_PER_LITER 150.0 ///< Rotor revolutions per liter. @@ -99,14 +98,16 @@ #define DIP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed. /// Macro converts flow rate to estimate PWM needed to achieve it. #define DIP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DIP_GEAR_RATIO * DIP_MOTOR_RPM_TO_PWM_DC_FACTOR + DIP_PWM_ZERO_OFFSET ) +/// Conversion from PWM duty cycle % to commanded pump motor speed. +#define DIP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - DIP_PWM_ZERO_OFFSET) * 4000.0 ) #define DIAL_IN_PUMP_ADC_FULL_SCALE_V 3.0 ///< BP analog signals are 0-3V (while int. ADC ref V may be different). #define DIAL_IN_PUMP_ADC_ZERO 1998 ///< Mid-point (zero) for ADC readings. ///< Macro converts a 12-bit ADC reading to a signed 16-bit value. #define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)DIAL_IN_PUMP_ADC_ZERO ) /// Measured dialIn flow is filtered w/ moving average. -#define SIZE_OF_ROLLING_AVG ( ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) * 10 ) +#define SIZE_OF_ROLLING_AVG ( ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) * DIP_CONTROL_INTERVAL_SEC ) /// Dialysate flow sensor signal strength low alarm persistence. #define FLOW_SIG_STRGTH_ALARM_PERSIST ( 5 * MS_PER_SECOND ) @@ -223,7 +224,6 @@ static void checkDialInPumpFlowAgainstSpeed( void ); static void checkDialInPumpMCCurrent( void ); static void checkDialInFlowSensorSignalStrength( void ); -static U32 getPublishDialInFlowDataInterval( void ); static BOOL processCalibrationData( void ); /*********************************************************************//** @@ -260,6 +260,7 @@ initPersistentAlarm( ALARM_ID_HD_DP_FLOW_READ_TIMEOUT_ERROR, 0, DIALYSATE_FLOW_FAST_READ_TO_PERSIST ); initPersistentAlarm( ALARM_ID_HD_DP_FLOW_SLOW_READ_TIMEOUT_ERROR, 0, DIALYSATE_FLOW_SLOW_READ_TO_PERSIST ); initPersistentAlarm( ALARM_ID_HD_DP_FLOW_SENSOR_ERROR, 0, DIALYSATE_FLOW_COMM_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_DIAL_IN_FLOW_OUT_OF_RANGE, 0, DIP_MAX_FLOW_RATE_OUT_OF_RANGE_PERSIST ); } /*********************************************************************//** @@ -280,8 +281,10 @@ // Direction change while pump is running is not allowed if ( ( FALSE == isDialInPumpOn ) || ( 0 == flowRate ) || ( dir == dialInPumpDirectionSet ) ) { +#ifndef NO_PUMP_FLOW_LIMITS // Verify flow rate - if ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) + if ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) +#endif { resetDialInFlowMovingAverage(); targetDialInFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); @@ -320,10 +323,12 @@ } result = TRUE; } +#ifndef NO_PUMP_FLOW_LIMITS else // Requested flow rate too high { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_DIAL_IN_FLOW_SET_TOO_HIGH, flowRate ) - } + } +#endif } return result; @@ -579,14 +584,11 @@ else if ( dialInPumpPWMDutyCyclePctSet >= dialInPumpPWMDutyCyclePct ) { resetDialInFlowMovingAverage(); + dialInPumpPWMDutyCyclePctSet = dialInPumpPWMDutyCyclePct; resetPIController( PI_CONTROLLER_ID_DIALYSATE_FLOW, dialInPumpPWMDutyCyclePctSet ); dialInPumpControlModeSet = dialInPumpControlMode; - // If open loop mode, set PWM to requested duty cycle where it will stay during control state - if ( dialInPumpControlModeSet == PUMP_CONTROL_MODE_OPEN_LOOP ) - { - dialInPumpPWMDutyCyclePctSet = dialInPumpPWMDutyCyclePct; - setDialInPumpControlSignalPWM( dialInPumpPWMDutyCyclePct ); - } + setDialInPumpControlSignalPWM( dialInPumpPWMDutyCyclePctSet ); + dipControlTimerCounter = 0; result = DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE; } // Continue ramp up @@ -621,14 +623,11 @@ else if ( dialInPumpPWMDutyCyclePctSet <= dialInPumpPWMDutyCyclePct ) { resetDialInFlowMovingAverage(); + dialInPumpPWMDutyCyclePctSet = dialInPumpPWMDutyCyclePct; resetPIController( PI_CONTROLLER_ID_DIALYSATE_FLOW, dialInPumpPWMDutyCyclePctSet ); dialInPumpControlModeSet = dialInPumpControlMode; - // If open loop mode, set PWM to requested duty cycle where it will stay during control state - if ( dialInPumpControlModeSet == PUMP_CONTROL_MODE_OPEN_LOOP ) - { - dialInPumpPWMDutyCyclePctSet = dialInPumpPWMDutyCyclePct; - setDialInPumpControlSignalPWM( dialInPumpPWMDutyCyclePct ); - } + setDialInPumpControlSignalPWM( dialInPumpPWMDutyCyclePctSet ); + dipControlTimerCounter = 0; result = DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE; } // Continue ramp down @@ -696,7 +695,7 @@ static void stopDialInPump( void ) { isDialInPumpOn = FALSE; - dialInPumpPWMDutyCyclePctSet = 0.0; + dialInPumpPWMDutyCyclePctSet = DIP_PWM_ZERO_OFFSET; etpwmSetCmpA( etpwmREG2, 0 ); SET_DIP_STOP(); } @@ -744,26 +743,6 @@ /*********************************************************************//** * @brief - * The getPublishDialInFlowDataInterval function gets the dialIn flow data - * publication interval. - * @details Inputs: dialInFlowDataPublishInterval - * @details Outputs: none - * @return the current dialIn flow data publication interval (in task intervals). - *************************************************************************/ -U32 getPublishDialInFlowDataInterval( void ) -{ - U32 result = dialInFlowDataPublishInterval.data; - - if ( OVERRIDE_KEY == dialInFlowDataPublishInterval.override ) - { - result = dialInFlowDataPublishInterval.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief * The processCalibrationData function gets the calibration data and makes * sure it is valid by checking the calibration date. The calibration date * should not be 0. @@ -939,6 +918,19 @@ } return result; +} + +/*********************************************************************//** + * @brief + * The getDialInPumpPWMDutyCyclePct function gets the current dialIn pump + * PWM duty cycle percentage. + * @details Inputs: dialInPumpPWMDutyCyclePctSet + * @details Outputs: none + * @return the current dialIn pump PWM duty cycle percentage (0..1). + *************************************************************************/ +F32 getDialInPumpPWMDutyCyclePct( void ) +{ + return dialInPumpPWMDutyCyclePctSet; } /*********************************************************************//** @@ -953,7 +945,7 @@ static void publishDialInFlowData( void ) { // Publish dialIn flow data on interval - if ( ++dialInFlowDataPublicationTimerCounter >= getPublishDialInFlowDataInterval() ) + if ( ++dialInFlowDataPublicationTimerCounter >= getU32OverrideValue( &dialInFlowDataPublishInterval ) ) { DIALIN_PUMP_STATUS_PAYLOAD_T payload; @@ -1147,10 +1139,10 @@ static void checkDialInPumpSpeeds( void ) { F32 measMotorSpeed = getMeasuredDialInPumpSpeed(); - S32 cmdRate = targetDialInFlowRate; + F32 measMCMotorSpeed = fabs( getMeasuredDialInPumpMCSpeed() ); // Check for pump running while commanded off - if ( 0 == cmdRate ) + if ( 0 == targetDialInFlowRate ) { if ( measMotorSpeed > DIP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) { @@ -1172,21 +1164,23 @@ errorDialInMotorOffPersistTimerCtr = 0; } + // Checks that only occur when pump is running (and beyond ramp). if ( DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE == dialInPumpState ) { - F32 cmdMotorSpeed = ( (F32)cmdRate / (F32)ML_PER_LITER ) * DIP_REV_PER_LITER * DIP_GEAR_RATIO; + F32 cmdMotorSpeed = DIP_PWM_TO_MOTOR_SPEED_RPM( dialInPumpPWMDutyCyclePctSet ); F32 deltaMotorSpeed = fabs( measMotorSpeed - cmdMotorSpeed ); + F32 deltaMCMotorSpeed = fabs( measMCMotorSpeed - cmdMotorSpeed ); F32 measRotorSpeed = getMeasuredDialInPumpRotorSpeed(); F32 measMotorSpeedInRotorRPM = measMotorSpeed / DIP_GEAR_RATIO; F32 deltaRotorSpeed = fabs( measRotorSpeed - measMotorSpeedInRotorRPM ); // Check measured motor speed vs. commanded motor speed while controlling to target - if ( deltaMotorSpeed > DIP_MAX_MOTOR_SPEED_ERROR_RPM ) + if ( ( deltaMotorSpeed > DIP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > DIP_MAX_MOTOR_SPEED_ERROR_RPM ) ) { if ( ++errorDialInMotorSpeedPersistTimerCtr >= DIP_MOTOR_SPEED_ERROR_PERSIST ) { #ifndef DISABLE_PUMP_SPEED_CHECKS - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MOTOR_SPEED_CHECK, (F32)cmdRate, measMotorSpeed ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_DIAL_IN_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); #endif } } @@ -1230,6 +1224,16 @@ *************************************************************************/ static void checkDialInPumpFlowAgainstSpeed( void ) { + F32 flow = getMeasuredDialInFlowRate(); + + // Range check on measure DPi flow rate. +#ifndef DISABLE_PUMP_FLOW_CHECKS + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_DIAL_IN_FLOW_OUT_OF_RANGE, ( flow > DIP_MAX_FLOW_RATE ) || ( flow < DIP_MIN_FLOW_RATE ) ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_DIAL_IN_FLOW_OUT_OF_RANGE, flow ); + } +#endif + // Check only performed while in treatment mode and while we are in control to target state if ( ( MODE_TREA == getCurrentOperationMode() ) && ( DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE == dialInPumpState ) ) {