Index: firmware/App/Controllers/DialInFlow.c =================================================================== diff -u -r09e6cf9de34acf18f6e1138bf56ac0edb4821186 -r5f929b475f0143cd3597547e3c20a77a5abb6d9c --- firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 09e6cf9de34acf18f6e1138bf56ac0edb4821186) +++ firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 5f929b475f0143cd3597547e3c20a77a5abb6d9c) @@ -1,6 +1,6 @@ /************************************************************************** * -* Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. +* Copyright (c) 2019-2022 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. @@ -82,33 +82,35 @@ /// 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); +static const U32 DIP_MAX_FLOW_RATE_OUT_OF_RANGE_PERSIST = (1 * MS_PER_SECOND); /// Time threshold to trigger an alarm if Dialysate flow data has not arrived within 3 seconds static const U32 DIP_DIALYSATE_FLOW_DATA_ALARM_THRESHOLD = ((3 * 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. -#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 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 ) + +#define DIP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for dialIn pump motor (3500 RPM/1998 counts). +#define DIP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000238 ///< ~42 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 146.84 ///< Rotor revolutions per liter. /// Macro converts flow rate to motor RPM. #define DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( DIP_REV_PER_LITER / ML_PER_LITER ) #define DIP_GEAR_RATIO 32.0 ///< DialIn pump motor to dialIn pump gear ratio. #define DIP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed. -/// Macro converts flow rate to estimate PWM needed to achieve it. // TODO - I added 1.2 gain based on empirical data -#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 * 1.2 + DIP_PWM_ZERO_OFFSET ) + +/// 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 10 @@ -220,7 +222,7 @@ { U32 i; - stopDialInPump(); + signalDialInPumpHardStop(); setDialInPumpDirection( MOTOR_DIR_FORWARD ); // Zero rolling flow average buffer @@ -260,54 +262,60 @@ // Direction change while pump is running is not allowed if ( ( FALSE == isDialInPumpOn ) || ( 0 == flowRate ) || ( dir == dialInPumpDirectionSet ) ) { + S32 dirFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); + + // Don't interrupt pump control unless rate or mode is changing + if ( ( dirFlowRate != targetDialInFlowRate ) || ( mode != dialInPumpControlMode ) ) + { #ifndef NO_PUMP_FLOW_LIMITS - // Verify flow rate - if ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) + // Verify flow rate + if ( flowRate <= MAX_DIAL_IN_FLOW_RATE ) #endif - { - resetDialInFlowMovingAverage(); - targetDialInFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); - dialInPumpDirection = dir; - dialInPumpControlMode = mode; - // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed - dialInPumpPWMDutyCyclePct = DIP_PWM_FROM_ML_PER_MIN((F32)flowRate); // ~ 8% per 100 mL/min with a 10% zero offset added in (e.g. 100 mL/min = 8+10 = 18%) - - switch ( dialInPumpState ) { - case DIAL_IN_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp - if ( dialInPumpPWMDutyCyclePct < dialInPumpPWMDutyCyclePctSet ) - { - dialInPumpState = DIAL_IN_PUMP_RAMPING_DOWN_STATE; - } - break; - case DIAL_IN_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp - if ( dialInPumpPWMDutyCyclePct > dialInPumpPWMDutyCyclePctSet ) - { - dialInPumpState = DIAL_IN_PUMP_RAMPING_UP_STATE; - } - break; - case DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction - if ( dialInPumpPWMDutyCyclePctSet > dialInPumpPWMDutyCyclePct ) - { - dialInPumpState = DIAL_IN_PUMP_RAMPING_DOWN_STATE; - } - else - { - dialInPumpState = DIAL_IN_PUMP_RAMPING_UP_STATE; - } - break; - default: - // Ok - not all states need to be handled here - break; + resetDialInFlowMovingAverage(); + targetDialInFlowRate = dirFlowRate; + dialInPumpDirection = dir; + dialInPumpControlMode = mode; + // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed + dialInPumpPWMDutyCyclePct = DIP_PWM_FROM_ML_PER_MIN((F32)flowRate); // ~ 8% per 100 mL/min with a 10% zero offset added in (e.g. 100 mL/min = 8+10 = 18%) + + switch ( dialInPumpState ) + { + case DIAL_IN_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp + if ( dialInPumpPWMDutyCyclePct < dialInPumpPWMDutyCyclePctSet ) + { + dialInPumpState = DIAL_IN_PUMP_RAMPING_DOWN_STATE; + } + break; + case DIAL_IN_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp + if ( dialInPumpPWMDutyCyclePct > dialInPumpPWMDutyCyclePctSet ) + { + dialInPumpState = DIAL_IN_PUMP_RAMPING_UP_STATE; + } + break; + case DIAL_IN_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction + if ( dialInPumpPWMDutyCyclePctSet > dialInPumpPWMDutyCyclePct ) + { + dialInPumpState = DIAL_IN_PUMP_RAMPING_DOWN_STATE; + } + else + { + dialInPumpState = DIAL_IN_PUMP_RAMPING_UP_STATE; + } + break; + default: + // Ok - not all states need to be handled here + break; + } + result = TRUE; } - 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 + 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; @@ -325,7 +333,7 @@ targetDialInFlowRate = 0; stopDialInPump(); dialInPumpState = DIAL_IN_PUMP_OFF_STATE; - dialInPumpPWMDutyCyclePct = 0.0; + dialInPumpPWMDutyCyclePct = DIP_PWM_ZERO_OFFSET; dipControlTimerCounter = 0; resetPIController( PI_CONTROLLER_ID_DIALYSATE_FLOW, MIN_DIAL_IN_PUMP_PWM_DUTY_CYCLE ); } @@ -565,7 +573,7 @@ // Have we essentially reached zero speed if ( dialInPumpPWMDutyCyclePctSet < (MAX_DIAL_IN_PUMP_PWM_STEP_DN_CHANGE + DIP_PWM_ZERO_OFFSET) ) { - stopDialInPump(); + signalDialInPumpHardStop(); result = DIAL_IN_PUMP_OFF_STATE; } // Have we reached end of ramp down? @@ -612,7 +620,8 @@ newPWM = runPIController( PI_CONTROLLER_ID_DIALYSATE_FLOW, tgtFlow, actFlow ); dialInPumpPWMDutyCyclePctSet = newPWM; - setDialInPumpControlSignalPWM( newPWM ); + setDialInPumpControlSignalPWM( newPWM ); + signalDialOutControl(); } dipControlTimerCounter = 0; } @@ -1297,7 +1306,6 @@ } if ( ctrlMode < NUM_OF_PUMP_CONTROL_MODES ) { - targetDialInFlowRate = value; result = setDialInPumpTargetFlowRate( abs(value), dir, (PUMP_CONTROL_MODE_T)ctrlMode ); } }