@@ -63,6 +63,7 @@ use prio::realtime_priority;
6363const MAX_AGE : Duration = Duration :: from_millis ( 300 ) ;
6464const THREAD_INTERVAL : Duration = Duration :: from_millis ( 100 ) ;
6565const TASK_INTERVAL : Duration = Duration :: from_millis ( 200 ) ;
66+ const TURN_ON_ERROR_GRACE_PERIOD : Duration = Duration :: from_millis ( 600 ) ;
6667const MAX_CURRENT : f32 = 5.0 ;
6768const MAX_VOLTAGE : f32 = 48.0 ;
6869const MIN_VOLTAGE : f32 = -1.0 ;
@@ -353,6 +354,12 @@ impl DutPwrThread {
353354 }
354355 } ;
355356
357+ // The grace period contains the number of loop iterations until
358+ // we start handling over/under voltage and overcurrent events.
359+ // This counts down to zero after turning on the output.
360+ // And is kept at TURN_ON_ERROR_GRACE_PERIOD while the output is off.
361+ let mut grace_period = TURN_ON_ERROR_GRACE_PERIOD ;
362+
356363 // Run as long as there is a strong reference to `tick`.
357364 // As tick is a private member of the struct this is equivalent
358365 // to running as long as the DutPwrThread was not dropped.
@@ -413,45 +420,61 @@ impl DutPwrThread {
413420 . swap ( OutputRequest :: Idle as u8 , Ordering :: Relaxed )
414421 . into ( ) ;
415422
416- // Don't even look at the requests if there is an ongoing
417- // overvoltage condition. Instead turn the output off and
418- // go back to measuring.
419- if volt > MAX_VOLTAGE {
420- turn_off_with_reason (
421- OutputState :: OverVoltage ,
422- & pwr_line,
423- & discharge_line,
424- & state,
425- ) ;
426-
427- continue ;
428- }
423+ // Checking for MAX_VOLTAGE, MIN_VOLTAGE, MAX_CURRENT error conditions while
424+ // the DUT power switch is off does not make a lot of sense,
425+ // considering the way we measure these values right now (behind the DUT power switch).
426+ // And what would we even do in this case? Turn the output even more off?
427+ // If we see one of these error conditions while the output is off it is
428+ // likely due to our high-impedance measurements and not due to a real error.
429+ // Ignore these kinds of errors while the output is off and for a few
430+ // THREAD_INTERVALs after turning it on.
431+ grace_period = match state. load ( Ordering :: Relaxed ) . into ( ) {
432+ OutputState :: On => grace_period. saturating_sub ( THREAD_INTERVAL ) ,
433+ OutputState :: Off
434+ | OutputState :: OffFloating
435+ | OutputState :: Changing
436+ | OutputState :: InvertedPolarity
437+ | OutputState :: OverCurrent
438+ | OutputState :: OverVoltage
439+ | OutputState :: RealtimeViolation => TURN_ON_ERROR_GRACE_PERIOD ,
440+ } ;
429441
430- // Don't even look at the requests if there is an ongoin
431- // polarity inversion. Turn off, go back to start, do not
432- // collect $200.
433- if volt < MIN_VOLTAGE {
434- turn_off_with_reason (
435- OutputState :: InvertedPolarity ,
436- & pwr_line,
437- & discharge_line,
438- & state,
439- ) ;
440-
441- continue ;
442- }
442+ if grace_period == Duration :: ZERO {
443+ // At this point the output is on and has been on for
444+ // TURN_ON_ERROR_GRACE_PERIOD, so we start checking for error conditions.
445+
446+ if volt > MAX_VOLTAGE {
447+ turn_off_with_reason (
448+ OutputState :: OverVoltage ,
449+ & pwr_line,
450+ & discharge_line,
451+ & state,
452+ ) ;
443453
444- // Don't even look at the requests if there is an ongoin
445- // overcurrent condition.
446- if curr > MAX_CURRENT {
447- turn_off_with_reason (
448- OutputState :: OverCurrent ,
449- & pwr_line,
450- & discharge_line,
451- & state,
452- ) ;
453-
454- continue ;
454+ continue ;
455+ }
456+
457+ if volt < MIN_VOLTAGE {
458+ turn_off_with_reason (
459+ OutputState :: InvertedPolarity ,
460+ & pwr_line,
461+ & discharge_line,
462+ & state,
463+ ) ;
464+
465+ continue ;
466+ }
467+
468+ if curr > MAX_CURRENT {
469+ turn_off_with_reason (
470+ OutputState :: OverCurrent ,
471+ & pwr_line,
472+ & discharge_line,
473+ & state,
474+ ) ;
475+
476+ continue ;
477+ }
455478 }
456479
457480 // There is no ongoing fault condition, so we could e.g. turn
@@ -742,4 +765,61 @@ mod tests {
742765 assert_eq ! ( pwr_line. stub_get( ) , 1 - PWR_LINE_ASSERTED ) ;
743766 assert_eq ! ( discharge_line. stub_get( ) , DISCHARGE_LINE_ASSERTED ) ;
744767 }
768+
769+ #[ test]
770+ fn grace_period ( ) {
771+ let mut wtb = WatchedTasksBuilder :: new ( ) ;
772+ let pwr_line = find_line ( "DUT_PWR_EN" ) . unwrap ( ) ;
773+ let discharge_line = find_line ( "DUT_PWR_DISCH" ) . unwrap ( ) ;
774+
775+ let ( adc, dut_pwr) = {
776+ let mut bb = BrokerBuilder :: new ( ) ;
777+ let adc = block_on ( Adc :: new ( & mut bb, & mut wtb) ) . unwrap ( ) ;
778+ let led = Topic :: anonymous ( None ) ;
779+
780+ let dut_pwr = block_on ( DutPwrThread :: new (
781+ & mut bb,
782+ & mut wtb,
783+ adc. pwr_volt . clone ( ) ,
784+ adc. pwr_curr . clone ( ) ,
785+ led,
786+ ) )
787+ . unwrap ( ) ;
788+
789+ ( adc, dut_pwr)
790+ } ;
791+
792+ // Set acceptable voltage / current
793+ adc. pwr_volt . fast . set ( MAX_VOLTAGE * 0.99 ) ;
794+ adc. pwr_curr . fast . set ( MAX_CURRENT * 0.99 ) ;
795+
796+ println ! ( "Turn Off" ) ;
797+ dut_pwr. request . set ( OutputRequest :: Off ) ;
798+ block_on ( sleep ( Duration :: from_millis ( 500 ) ) ) ;
799+ assert_eq ! ( pwr_line. stub_get( ) , 1 - PWR_LINE_ASSERTED ) ;
800+ assert_eq ! ( discharge_line. stub_get( ) , DISCHARGE_LINE_ASSERTED ) ;
801+ assert_eq ! ( block_on( dut_pwr. state. get( ) ) , OutputState :: Off ) ;
802+
803+ println ! ( "Set overvoltage" ) ;
804+ adc. pwr_volt . fast . set ( MAX_VOLTAGE * 1.01 ) ;
805+ block_on ( sleep ( Duration :: from_millis ( 500 ) ) ) ;
806+
807+ println ! ( "Check if output stays off and does not go into error state" ) ;
808+ assert_eq ! ( pwr_line. stub_get( ) , 1 - PWR_LINE_ASSERTED ) ;
809+ assert_eq ! ( discharge_line. stub_get( ) , DISCHARGE_LINE_ASSERTED ) ;
810+ assert_eq ! ( block_on( dut_pwr. state. get( ) ) , OutputState :: Off ) ;
811+
812+ println ! ( "Turn On (with overvoltage applied)" ) ;
813+ dut_pwr. request . set ( OutputRequest :: On ) ;
814+ block_on ( sleep ( Duration :: from_millis ( 400 ) ) ) ;
815+ assert_eq ! ( pwr_line. stub_get( ) , PWR_LINE_ASSERTED ) ;
816+ assert_eq ! ( discharge_line. stub_get( ) , 1 - DISCHARGE_LINE_ASSERTED ) ;
817+ assert_eq ! ( block_on( dut_pwr. state. get( ) ) , OutputState :: On ) ;
818+
819+ println ! ( "Go into overvoltage error" ) ;
820+ block_on ( sleep ( Duration :: from_millis ( 500 ) ) ) ;
821+ assert_eq ! ( pwr_line. stub_get( ) , 1 - PWR_LINE_ASSERTED ) ;
822+ assert_eq ! ( discharge_line. stub_get( ) , DISCHARGE_LINE_ASSERTED ) ;
823+ assert_eq ! ( block_on( dut_pwr. state. get( ) ) , OutputState :: OverVoltage ) ;
824+ }
745825}
0 commit comments